文章目录
- 一、项目内容
- 二、各步骤的代码实现
- 1、爬取数据
- 2、数据处理
- 3、建立模型训练
- 4、自定义数据进行预测
一、项目内容
- 1、爬取数据
- 本次项目的数据是某购物平台中某个产品的优质评价内容和差评内容
- 采用爬虫的 selenium 方法进行爬取数据内容,并将爬取的内容分别存放在两个文本文件中
- 2、数据处理
- 分别读取存放数据的两个文本文件
- 分别对优质评价和差评的内容进行分词
- 导入停用词库,对数据进行去除停用词的操作,去除停用词可以减少数据集的噪音,提高后续处理步骤的效率和准确性
- 停用词:停用词(Stop Words)是指在文本处理、自然语言处理(NLP)或信息检索(IR)中,那些对于理解文档或查询的真实意图没有帮助或贡献很小,通常会被忽略或从文本中移除的词汇。这些词汇通常是语言中最常见、最普遍的词汇,如“的”、“是”、“在”、“了”、“和”等(在中文中),以及“the”、“is”、“at”、“of”、“and”等(在英文中)
- 3、建立模型训练
- 给每个数据添加数字标签
- 数据切分:训练集特征、测试集特征、训练集标签、测试集标签
- 将所有的词转换为词向量
- 导入朴素贝叶斯分类器
- 4、自定义数据进行测试
- 可以自定义一些评价,通过处理后传入模型进行预测
二、各步骤的代码实现
1、爬取数据
-
优质评价与差评的爬取步骤基本上都是一致的,因为二者的标签布局都是一样的,只是在url上有略微的区别
-
具体的爬取步骤就不再细说了,在我之前所发布的爬虫内容中都有详解
-
用的是爬虫的 selenium 方法,结合下面两张图片和代码内容理解(在网页界面中按F12查看元素结构)
-
优质评价的获取
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.edge.options import Options import time if __name__ == '__main__': # 创建文本用于存放优质评价内容 fp = open("hp.txt", "w", encoding="utf8") # 通过for循环爬取每一页的优质评价内容,由于内容太多,只爬取200页 for i in range(1, 200): # 设置无头模式(爬取时不显示网页界面) opt = Options() opt.add_argument("--headless") driver = webdriver.Edge(options=opt) # driver = webdriver.Edge() # 请求页面 driver.get( f"https://review.suning.com/cluster_cmmdty_review/cluster-38249278-000000012389328846-" f"0000000000-{i}-good.htm?originalCmmdtyType=general&safp=d488778a.10004.loverRight.166") # 强制等待 time.sleep(3) # 获取存放优质评价内容的所有div标签内容 div_list = driver.find_elements(By.XPATH, "//div[@class='rv-target-item']/div") # print(div_list) # 循环遍历每一个div标签,获取每个用户的优质评价 for div in div_list: good_p = div.find_element(By.XPATH, "div/div/div[2]/div[2]/p").text # print(good_p) # 将优质评价内容存写入文本中,并进行换行 fp.write(good_p + "\n") # 关闭请求 driver.close() # 关闭文本文件 fp.close()
-
差评的获取
if __name__ == '__main__': # 创建文本用于存放差评内容 fp = open("cp.txt", "w", encoding="utf8") # for 循环爬取每一页的差评内容(差评一共只有两页) for i in range(1, 3): # 设置无头模式(爬取时不显示网页界面) opt = Options() opt.add_argument("--headless") driver = webdriver.Edge(options=opt) # driver = webdriver.Edge() # 请求页面 driver.get( f"https://review.suning.com/cluster_cmmdty_review/cluster-38249278-000000012389328846-" f"0000000000-{i}-bad.htm?originalCmmdtyType=general&safp=d488778a.10004.loverRight.166") # 强制等待 time.sleep(3) # 获取存放差评内容的所有div标签内容 div_list = driver.find_elements(By.XPATH, "//div[@class='rv-target-item']/div") # print(div_list) # 循环遍历每一个div标签,获取每个用户的差评 for div in div_list: good_p = div.find_element(By.XPATH, "div/div/div[2]/div[2]/p").text # print(good_p) # # 将差评内容存写入文本中,并进行换行 fp.write(good_p + "\n") # 关闭请求 driver.close() # 关闭文本文件 fp.close()
2、数据处理
-
1.读取数据
-
2.分词
- 可参考以下文章对jieba分词进行理解
- 链接:https://blog.csdn.net/weixin_73504499/article/details/141688513?spm=1001.2014.3001.5501
-
3.去停用词
"""数据读取和处理""" import pandas as pd """读取数据""" # 差评 cp_content = pd.read_table("cp.txt") # 好评 yzpj_content = pd.read_table("hp.txt") """分词""" import jieba # 对差评分词 cp_segments = [] contents = cp_content.content.values.tolist() # 将content列数据取出并转化为list格式;目的是分别 jieba.lcut分词 for content in contents: results = jieba.lcut(content) if len(results) > 1: # 当分词之后,这条评论如果只有1个词内容,则丢弃 cp_segments.append(results) # 将分词后的内容添加到列表cp_segments中 # 分词结果储存在新的数据框中 cp_fc_results = pd.DataFrame({'content': cp_segments}) # 对优质评价分词(与差评相同) yzpj_segments = [] contents = yzpj_content.content.values.tolist() for content in contents: results = jieba.lcut(content) if len(results) > 1: yzpj_segments.append(results) # 分词结果储存在新的数据框中 yzpj_fc_results = pd.DataFrame({'content': yzpj_segments}) """去停用词""" # 导入停用词库 stopwords = pd.read_csv(r"StopwordsCN.txt", encoding='utf-8', engine='python', index_col=False) # 定义去除停用词函数 def drop_stopwords(contents, stopwords): segments_clean = [] for content in contents: line_clean = [] for word in content: if word in stopwords: continue line_clean.append(word) segments_clean.append(line_clean) return segments_clean stopwords = stopwords.stopword.values.tolist() # 停用词转为list格式 # 差评去停用词 contents = cp_fc_results.content.values.tolist() # DataFrame格式转为list格式 cp_fc_contents_clean_s = drop_stopwords(contents, stopwords) # 调用去除停用词函数 # 好评去停用词 contents = yzpj_fc_results.content.values.tolist() # DataFrame格式转为list格式 yzpj_fc_contents_clean_s = drop_stopwords(contents, stopwords) # 调用去除停用词函数
3、建立模型训练
-
1.给每个数据添加数字标签
-
2.数据切分:训练集特征、测试集特征、训练集标签、测试集标签
-
3.将所有的词转换为词向量
- 可参考以下文章对 CountVectorizer() 词向量方法进行理解
- 链接:https://blog.csdn.net/weixin_73504499/article/details/141754383?spm=1001.2014.3001.5501
-
4.导入朴素贝叶斯分类器
"""朴素贝叶斯分类""" '''1.给每个数据添加数字标签''' cp_train = pd.DataFrame({'segments_clean': cp_fc_contents_clean_s, 'label': 1}) # 差评为 1 yzpj_train = pd.DataFrame({'segments_clean': yzpj_fc_contents_clean_s, 'label': 0}) # 好评为 0 pj_train = pd.concat([cp_train, yzpj_train]) # 将差评与好评数据拼接在一起,成为一个完整的数据集 '''2.数据切分:训练集特征、测试集特征、训练集标签、测试集标签''' from sklearn.model_selection import train_test_split # 默认切分为 训练集75% 测试集25% # 传入数据和标签,设定随机种子 x_train, x_test, y_train, y_test = \ train_test_split(pj_train['segments_clean'].values, pj_train['label'].values, random_state=0) """3.将所有的词转换为词向量""" '''将训练集数据转换为词向量 :CountVectorizer()方法 所能识别的列表类型''' train_words = [] for line_index in range(len(x_train)): train_words.append(' '.join(x_train[line_index])) #print(train_words) # 导入词向量方法:CountVectorizer from sklearn.feature_extraction.text import CountVectorizer # lowercase参数的功能:把所有的词是否需要转换为小写。False # max_features:表示只提取前4000个词作为词库 vec = CountVectorizer(max_features=4000, lowercase=False, ngram_range=(1, 1)) vec.fit(train_words) '''4.导入朴素贝叶斯分类器''' from sklearn.naive_bayes import MultinomialNB # alpha 是一个平滑参数 # 这个参数的作用是防止在训练过程中出现零概率的情况,即某个特征在某个类别中从未出现过 classifier = MultinomialNB(alpha=0.1) # 对训练集进行训练 classifier.fit(vec.transform(train_words), y_train) # 对训练集进行预测 train_predict = classifier.predict(vec.transform(train_words)) # print(train_predict) from sklearn import metrics # 对训练集预测结果进行评估 print(metrics.classification_report(y_train, train_predict)) # 将测试集数据转换成 词向量方法:vec = CountVectorizer() 可以识别的列表类型 test_words = [] for line_index in range(len(x_test)): test_words.append(' '.join(x_test[line_index])) # 对测试集进行预测 test_predict = classifier.predict(vec.transform(test_words)) # print(test_predict) # 对测试集预测结果进行评估 print(metrics.classification_report(y_test, test_predict)
- 结果如下:
- 通过召回率(recall)这一评价指标可以看出此模型的效果还是不错的,但是由于优质评价和差评数据量的严重不均衡导致了精确率(precision)和 F1值(F1-score)的效果并不是很好
- 结果如下:
4、自定义数据进行预测
-
将处理自定义评价的内容封装在函数中,传入自定义的评价,输出预测结果是优质好评还是差评
def zidingyi(s): # 分词,并存入列表中 s_fc_2 = [] s_fc = jieba.lcut(sentence=s) s_fc_2.append(s_fc) # 去停用词 s_fc_content = drop_stopwords(s_fc_2, stopwords) # 转换为词向量 CountVectorizer 所能识别的列表类型 test_s = [] for line_index in range(len(s_fc_content)): test_s.append(' '.join(s_fc_content[line_index])) # 传入模型预测结果 yc_predict = classifier.predict(vec.transform(test_s)) print(yc_predict) zidingyi(s='这玩意真好,我很喜欢') zidingyi(s='垃圾玩意,包装太差,很廉价的感觉')
- 结果如下:
- 在添加数据标签时规定了优质评价为 0 ,差评 为 1
- 可以看出此模型的预测效果还是很准确的
- 少量的预测可能不具有说服力,可以多自定义一些评价传入模型进行预测
- 结果如下: