说明:这是一个机器学习实战项目(附带数据+代码),如需数据+完整代码可以直接到文章最后获取。
1.项目背景
随着信息化社会的发展,互联网成为方便、快捷的信息获取渠道之一。在电子商务和社会网站中,大量非结构化的评论文本作为最直观的用户体验数据被保存下来。如何利用这些文字信息归纳出用户对某一事、物的观点态度成为自然语言(NLP)领域一项重要任务。
文本情感分析又称文本意见挖掘,是自然语言处理领域最优吸引力的研究方向之一。文本情感分析通过计算语言学知识量化处理得到一段文字的观点态度和情感倾向。
淘宝作为一个电子商务平台,越来越受欢迎,2020年天猫双十一营业额超过3000多亿。商家销售的商品更是不计其数,每个商品的评论更是非常之多,本项目就是针对商品的评论数据通过建立循环神经网络模型进行情感倾向的分析。
2.数据采集
通过Python撰写爬虫程序,爬取天猫华为手机商品的评论数据。
爬取的数据集如下:
数据集:data_comment.xlsx
数据字段包括:nickname、ratedate、auctionSku、ratecontent
在实际应用中,根据自己的数据进行替换即可。
特征数据:评论文本
标签数据:情感倾向(好评(2)、中评(1)、差评(0))
作为演示,我只弄了75条特征、标签数据,所以最后模型评估的时候,测试集再100次训练下出现了过拟合。
爬虫代码详见:爬虫.py
def GetInfo(num): # 定义需要的字段 nickname = [] auctionSku = [] ratecontent = [] ratedate = [] # 循环获取每一页评论 for i in range(num): # 头文件,没有头文件会返回错误的js headers = { 'cookie': 'cna=qMU/EQh0JGoCAW5QEUJ1/zZm; enc=DUb9Egln3%2Fi4NrDfzfMsGHcMim6HWdN%2Bb4ljtnJs6MOO3H3xZsVcAs0nFao0I2uau%2FbmB031ZJRvrul7DmICSw%3D%3D; lid=%E5%90%91%E6%97%A5%E8%91%B5%E7%9B%9B%E5%BC%80%E7%9A%84%E5%A4%8F%E5%A4%A9941020; otherx=e%3D1%26p%3D*%26s%3D0%26c%3D0%26f%3D0%26g%3D0%26t%3D0; hng=CN%7Czh-CN%7CCNY%7C156; x=__ll%3D-1%26_ato%3D0; t=2c579f9538646ca269e2128bced5672a; _m_h5_tk=86d64a702eea3035e5d5a6024012bd40_1551170172203; _m_h5_tk_enc=c10fd504aded0dc94f111b0e77781314; uc1=cookie16=V32FPkk%2FxXMk5UvIbNtImtMfJQ%3D%3D&cookie21=U%2BGCWk%2F7p4mBoUyS4E9C&cookie15=UtASsssmOIJ0bQ%3D%3D&existShop=false&pas=0&cookie14=UoTZ5bI3949Xhg%3D%3D&tag=8&lng=zh_CN; uc3=vt3=F8dByEzZ1MVSremcx%2BQ%3D&id2=UNcPuUTqrGd03w%3D%3D&nk2=F5RAQ19thpZO8A%3D%3D&lg2=U%2BGCWk%2F75gdr5Q%3D%3D; tracknick=tb51552614; _l_g_=Ug%3D%3D; ck1=""; unb=3778730506; lgc=tb51552614; cookie1=UUBZRT7oNe6%2BVDtyYKPVM4xfPcfYgF87KLfWMNP70Sc%3D; login=true; cookie17=UNcPuUTqrGd03w%3D%3D; cookie2=1843a4afaaa91d93ab0ab37c3b769be9; _nk_=tb51552614; uss=""; csg=b1ecc171; skt=503cb41f4134d19c; _tb_token_=e13935353f76e; x5sec=7b22726174656d616e616765723b32223a22393031623565643538663331616465613937336130636238633935313935363043493362302b4d46454e76646c7243692b34364c54426f4d4d7a63334f44637a4d4455774e6a7378227d; l=bBIHrB-nvFBuM0pFBOCNVQhjb_QOSIRYjuSJco3Wi_5Bp1T1Zv7OlzBs4e96Vj5R_xYB4KzBhYe9-etui; isg=BDY2WCV-dvURoAZdBw3uwj0Oh2yUQwE5YzQQ9qAfIpm149Z9COfKoZwV-_8q0HKp', 'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36', 'referer': 'https://detail.tmall.com/item.htm?spm=a1z10.5-b-s.w4011-17205939323.51.30156440Aer569&id=41212119204&rn=06f66c024f3726f8520bb678398053d8&abbucket=19&on_comment=1&sku_properties=134942334:3226348', 'accept': '*/*', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9' } # 解析JS文件内容 content = requests.get(COMMENT_PAGE_URL[i], headers=headers).text print(content) nk = re.findall('"displayUserNick":"(.*?)"', content) nickname.extend(nk) # print(nk) auctionSku.extend(re.findall('"auctionSku":"(.*?)"', content)) ratecontent.extend(re.findall('"rateContent":"(.*?)"', content)) ratedate.extend(re.findall('"rateDate":"(.*?)"', content)) data = pd.DataFrame(columns=['nickname', 'ratedate', 'auctionSku', 'ratecontent']) data['nickname'] = nickname data['ratedate'] = ratedate data['auctionSku'] = auctionSku data['ratecontent'] = ratecontent print(data.head()) data.to_excel('data_comment_zcy.xlsx', index=False, encoding='utf-8')
3.数据预处理
爬虫爬取下来的数据格式如下:
用户户没有意义,直接去掉;日期转换为以天为单位;auctionSku字段以分号进行分割拆分为网络类型、机身颜色、套餐类型、存储容量4个数据项,方便后续进行数据分析,清洗后的数据如下:
4.探索性数据分析
1)按月统计订单完成交易时间的订单个数:
通过上图可以看到,2021年8月份完成订单交易最多,其次是2021年6月份。
data_group = df_data.groupby('月份').count() data_group['ratecontent'].plot(kind='pie', title='按月统计订单完成交易时间的订单个数') plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 plt.show()
2)按机型类型进行统计分析:
上图可以看到,SA/NSA双模(5G)、亮黑色、套餐一、8+256GB最多。
data_group = df_data.groupby(['网络类型', '机身颜色', '套餐类型', '存储容量']).count() data_group['ratecontent'].plot(kind='bar', title='按机型类型进行统计分析') plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 plt.show()
3)按机身颜色进行统计分析:
从上图可以看出,亮黑色最受欢迎。
data_group = df_data.groupby(['机身颜色']).count() data_group['ratecontent'].plot(kind='barh', title='按机身颜色进行统计分析') plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 plt.show()
3)按存储容量进行统计分析:
从上图可以看出,大部分人都喜欢大容量的。
data_group = df_data.groupby(['存储容量']).count() data_group['ratecontent'].plot(kind='pie', title='按存储容量进行统计分析') plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 plt.show()
4)制作评论数据词云图
分词:
def SegText(): import jieba # 待分词的文本路径 sourceTxt = 'source.txt' # 分好词后的文本路径 targetTxt = 'target.txt' # 对文本进行操作 with open(sourceTxt, 'r', encoding='utf-8') as sourceFile, open(targetTxt, 'a+', encoding='utf-8') as targetFile: for line in sourceFile: seg = jieba.cut(line.strip(), cut_all=False) # 分好词之后之间用/隔断 output = '/'.join(seg) targetFile.write(output) targetFile.write('\n') print('写入成功!') sourceFile.close() targetFile.close()
词频统计:
词云图:
def Word_Cloud(): # 输出词频前N的词语并且以str的形式返回 txt = open("shuchu.txt", "r", encoding='utf-8').read() # 打开txt文件,要和python在同一文件夹 words = jieba.lcut(txt) # 精确模式,返回一个列表 counts = {} # 创建字典 for word in words: if len(word) == 1: # 把意义相同的词语归一 continue elif word == "三炮" or word == "#" or word== "##" or word=="24" or word=="RAP" or word=="video": rword = " " else: rword = word counts[rword] = counts.get(rword, 0) + 1 # 字典的运用,统计词频 items = list(counts.items()) # 返回所有键值对P168 items.sort(key=lambda x: x[1], reverse=True) # 降序排序 N = eval(input("请输入N:代表输出的数字个数")) # 这里输入300就行,因为shuchu01.txt里面的数据有限 wordlist = list() # 创建列表并赋值 for i in range(N): word, count = items[i] # print("{0:<10}{1:<5}".format(word, count)) # 输出前N个词频的词语 wordlist.append(word) # 把词语word放进一个列表 a = ' '.join(wordlist) # 把列表转换成str wl为str类型,所以需要转换 return a def create_word_cloud(): wl = Word_Cloud() # 调用函数获取str!! # 图片名字 需一致 cloud_mask = np.array(Image.open("love.jpg")) # 词云的背景图,需要颜色区分度高 wc = WordCloud( background_color="black", # 背景颜色 mask=cloud_mask, # 背景图cloud_mask max_words=100, # 最大词语数目 font_path='simsun.ttf', # 调用font里的simsun.tff字体,需要提前安装 height=1200, # 设置高度 width=1600, # 设置宽度 max_font_size=1000, # 最大字体号 random_state=1000, # 设置随机生成状态,即有多少种配色方案
5.特征工程
1)用Tokenizer给文本分词
评论句子已经被分解为单词
每个单词已经被分配一个唯一的词典索引
分词后输出的值是列表类型的数据:
2)通过直方图显示各条评论中单词个数的分布情况
上图中的评论长度分布情况表明多数评论的词数在5以内,所以我们只需要处理前5个词,就能够判定绝大多数评论的类型。如果这个数目太大,那么将来构造出的词嵌入张量就达不到密集矩阵的效果。
word_per_comment = [len(comment) for comment in X_train_tokenized_lst] plt.hist(word_per_comment, bins=np.arange(0, 5, 0.2)) # 显示评论长度分布 plt.show()
6.LSTM建模
1)建立LSTM分类模型,模型参数如下:
编号
参数
1
loss=' sparse_categorical_crossentropy '
2
optimizer='adam'
3
metrics=['acc']
其它参数根据具体数据,具体设置。
2)神经网络概要
可以看到每层网络的类型、形状和参数。
一些其它的神经元图可以自行画。
3)训练过程展示
lstm = Sequential() # 贯序模型 lstm.add(Embedding(dictionary_size, embedding_vecor_length, input_length=max_comment_length)) # 加入词嵌入层 lstm.add(LSTM(100)) # 加入LSTM层 lstm.add(Dense(10, activation='relu')) # 加入全连接层 lstm.add(Dense(3, activation='softmax')) # 加入分类输出层 lstm.compile(loss='sparse_categorical_crossentropy', # 损失函数 optimizer='adam', # 优化器 metrics=['acc']) # 评估指标 history = lstm.fit(X_train, y, validation_split=0.3, epochs=100, batch_size=64)
7.模型评估
1)损失和准确率图
通过上图可以看到,针对测试集 训练100次有些过拟合了,主要原因是总共我只做了75条数据,训练集数据太少。实际操作中,数据集是远远大于这个的。
其它一些评估方法,大家可以自行选择。
def show_history(history): loss = history.history['loss'] val_loss = history.history['val_loss'] epochs = range(1, len(loss) + 1) plt.figure(figsize=(12, 4)) plt.subplot(1, 2, 1) plt.plot(epochs, loss, 'r', label='Training loss') plt.plot(epochs, val_loss, 'b', label='Test loss') plt.title('Training and Test loss') plt.xlabel('Epochs') plt.ylabel('Loss') plt.legend() acc = history.history['acc'] val_acc = history.history['val_acc'] plt.subplot(1, 2, 2) plt.plot(epochs, acc, 'r', label='Training acc') plt.plot(epochs, val_acc, 'b', label='Test acc') plt.title('Training and Test accuracy') plt.xlabel('Epochs') plt.ylabel('Accuracy') plt.legend() plt.show()
8.实际应用
在日常电子商务运营中,会出现新的评价数据,然后就可以运用此模型进行预测,准确定位客户对产品的评价,然后针对不同的客户要求来进行优化产品以及针对性营销。
本次机器学习项目实战所需的资料,项目资源如下:https://download.csdn.net/download/weixin_42163563/21987564