一、准备工作
1、数据导入
import numpy as np
import pandas as pd
data = pd.read_csv('/Users/liming/Downloads/review_star.csv')
print(data.shape)
data.head()
(10000, 3)
| reviewid | reviewbody | star | |
|---|---|---|---|
| 0 | 661655779 | 感谢大众点评的vip会员卷。很多好吃的都打折。去天河城吃饭顺便把喝的换了。两杯茶才9.9。简... | 40 |
| 1 | 661662037 | (9月26日就餐)这家的服务态度真是很奇葩了:在等餐时看到服务员在端豆浆上桌前,突然在碗里发... | 5 |
| 2 | 661662167 | 除了贵 没毛病 | 35 |
| 3 | 661674219 | 亲民,家门口,味道可以,主要是在家附近,吃点家常菜还是比较方便的,不做饭就在这里吃点,做的也... | 45 |
| 4 | 661677846 | 之前在会展中心店按过,觉得很不错,说上梅林也有一家店,刚好在附近办事,所以来了这里,装修风格... | 50 |
2、情感划分
# 查看 star 字段唯一值
print(pd.unique(data['star']))
[40 5 35 45 50 20 30 25 10 4 15]
我们的目的是分析文本的情感:积极或消极。 因此,这里设置阈值为30:star 小于30的为消极(0)、大于等于30的为积极(1)。
# 定义函数:根据用户评的星级来估计sentiment(情感)
def make_label(star):
if star >=30:
return 1
else:
return 0
# 运用 apply 方法得到新列
data["sentiment"] = data.star.apply(make_label)
data.head()
| reviewid | reviewbody | star | sentiment | |
|---|---|---|---|---|
| 0 | 661655779 | 感谢大众点评的vip会员卷。很多好吃的都打折。去天河城吃饭顺便把喝的换了。两杯茶才9.9。简... | 40 | 1 |
| 1 | 661662037 | (9月26日就餐)这家的服务态度真是很奇葩了:在等餐时看到服务员在端豆浆上桌前,突然在碗里发... | 5 | 0 |
| 2 | 661662167 | 除了贵 没毛病 | 35 | 1 |
| 3 | 661674219 | 亲民,家门口,味道可以,主要是在家附近,吃点家常菜还是比较方便的,不做饭就在这里吃点,做的也... | 45 | 1 |
| 4 | 661677846 | 之前在会展中心店按过,觉得很不错,说上梅林也有一家店,刚好在附近办事,所以来了这里,装修风格... | 50 | 1 |
data["reviewbody"] = data["reviewbody"].astype(str)
data.head()
| reviewid | reviewbody | star | sentiment | |
|---|---|---|---|---|
| 0 | 661655779 | 感谢大众点评的vip会员卷。很多好吃的都打折。去天河城吃饭顺便把喝的换了。两杯茶才9.9。简... | 40 | 1 |
| 1 | 661662037 | (9月26日就餐)这家的服务态度真是很奇葩了:在等餐时看到服务员在端豆浆上桌前,突然在碗里发... | 5 | 0 |
| 2 | 661662167 | 除了贵 没毛病 | 35 | 1 |
| 3 | 661674219 | 亲民,家门口,味道可以,主要是在家附近,吃点家常菜还是比较方便的,不做饭就在这里吃点,做的也... | 45 | 1 |
| 4 | 661677846 | 之前在会展中心店按过,觉得很不错,说上梅林也有一家店,刚好在附近办事,所以来了这里,装修风格... | 50 | 1 |
二、朴素贝叶斯方法
接下来使用sklearn实现朴素贝叶斯模型来进行情感分析。
1、分词
# 首先对评论数据进行分词
import jieba
def chinese_word_cut(mytext):
return " ".join(jieba.cut(mytext))
data['cut_comment'] = data["reviewbody"].apply(chinese_word_cut)
data.head()
Building prefix dict from the default dictionary ...
Loading model from cache /var/folders/zd/qhg48cw17_ncqf0rl48wz5rh0000gp/T/jieba.cache
Loading model cost 0.552 seconds.
Prefix dict has been built successfully.
| reviewid | reviewbody | star | sentiment | cut_comment | |
|---|---|---|---|---|---|
| 0 | 661655779 | 感谢大众点评的vip会员卷。很多好吃的都打折。去天河城吃饭顺便把喝的换了。两杯茶才9.9。简... | 40 | 1 | 感谢 大众 点评 的 vip 会员 卷 。 很多 好吃 的 都 打折 。 去 天河城 吃饭 ... |
| 1 | 661662037 | (9月26日就餐)这家的服务态度真是很奇葩了:在等餐时看到服务员在端豆浆上桌前,突然在碗里发... | 5 | 0 | ( 9 月 26 日 就餐 ) 这家 的 服务态度 真是 很 奇葩 了 : 在 等 餐时 看... |
| 2 | 661662167 | 除了贵 没毛病 | 35 | 1 | 除了 贵 没 毛病 |
| 3 | 661674219 | 亲民,家门口,味道可以,主要是在家附近,吃点家常菜还是比较方便的,不做饭就在这里吃点,做的也... | 45 | 1 | 亲民 , 家门口 , 味道 可以 , 主要 是 在家 附近 , 吃点 家常菜 还是 比较 方... |
| 4 | 661677846 | 之前在会展中心店按过,觉得很不错,说上梅林也有一家店,刚好在附近办事,所以来了这里,装修风格... | 50 | 1 | 之前 在 会展中心 店 按 过 , 觉得 很 不错 , 说 上 梅林 也 有 一家 店 , ... |
2、划分数据集
这里的特征X为分词后的评论数据 cut_comment,目标y为情感数据 sentiment。按8:2的比例切分为训练集和测试集。
X = data['cut_comment']
y = data['sentiment']
from sklearn.model_selection import train_test_split
# 划分测试集和训练集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=22)
3、词向量(数据处理)
电脑是没法识别文字的,只能识别数字。下面利用sklearn中的CountVectorizer方法将文本转化为词向量。
CountVectorizer(潜在语义分析方法)方法常用的参数:
- max_df:在超过这一比例的文档中出现的关键词(过于平凡),去除掉。
- min_df:在低于这一数量的文档中出现的关键词(过于独特),去除掉。
- token_pattern:主要是通过正则处理掉数字和标点符号。
- stop_words:设置停用词表,这样的词我们就不会统计出来(多半是虚拟词,冠词等等),需要列表结构,所以代码中定义了一个函数来处理停用词表。
from sklearn.feature_extraction.text import CountVectorizer
def get_custom_stopwords(stop_words_file):
with open(stop_words_file, encoding="ISO-8859-1") as f:
stopwords = f.read()
stopwords_list = stopwords.split('\n')
custom_stopwords_list = [i for i in stopwords_list]
return custom_stopwords_list
stop_words_file = '/Users/liming/Downloads/哈工大停用词表.txt'
stopwords = get_custom_stopwords(stop_words_file)
vect = CountVectorizer(max_df = 0.8,
min_df = 3,
token_pattern=u'(?u)\\b[^\\d\\W]\\w+\\b',
stop_words=frozenset(stopwords))
通过以下代码查看得到的数据:
# 不输出warning
import warnings
warnings.filterwarnings('ignore')
# 查看 vect
test = pd.DataFrame(vect.fit_transform(X_train).toarray(), columns=vect.get_feature_names())
test.head()
| and | app | a座 | b1 | b2 | bar | bb | bbq | brunch | bug | ... | 齐全 | 龙之梦 | 龙凤 | 龙利 | 龙利鱼 | 龙头 | 龙岗 | 龙湖 | 龙虾 | 龙门 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 rows × 8223 columns
4、模型训练(朴素贝叶斯算法)
from sklearn.naive_bayes import MultinomialNB
nb = MultinomialNB() # 构建朴素贝叶斯模型框架
X_train_vect = vect.fit_transform(X_train) # 将训练数据转化为词向量
nb.fit(X_train_vect, y_train) # 训练模型
train_score = nb.score(X_train_vect, y_train)# 计算准确率
print(train_score)
0.9715
5、模型测试
X_test_vect = vect.transform(X_test)
print(nb.score(X_test_vect, y_test))
0.958
将结果放入到data数据中:
X_vec = vect.transform(X)
nb_result = nb.predict(X_vec)
data['nb_result'] = nb_result
data.head()
| reviewid | reviewbody | star | sentiment | cut_comment | nb_result | |
|---|---|---|---|---|---|---|
| 0 | 661655779 | 感谢大众点评的vip会员卷。很多好吃的都打折。去天河城吃饭顺便把喝的换了。两杯茶才9.9。简... | 40 | 1 | 感谢 大众 点评 的 vip 会员 卷 。 很多 好吃 的 都 打折 。 去 天河城 吃饭 ... | 1 |
| 1 | 661662037 | (9月26日就餐)这家的服务态度真是很奇葩了:在等餐时看到服务员在端豆浆上桌前,突然在碗里发... | 5 | 0 | ( 9 月 26 日 就餐 ) 这家 的 服务态度 真是 很 奇葩 了 : 在 等 餐时 看... | 0 |
| 2 | 661662167 | 除了贵 没毛病 | 35 | 1 | 除了 贵 没 毛病 | 1 |
| 3 | 661674219 | 亲民,家门口,味道可以,主要是在家附近,吃点家常菜还是比较方便的,不做饭就在这里吃点,做的也... | 45 | 1 | 亲民 , 家门口 , 味道 可以 , 主要 是 在家 附近 , 吃点 家常菜 还是 比较 方... | 1 |
| 4 | 661677846 | 之前在会展中心店按过,觉得很不错,说上梅林也有一家店,刚好在附近办事,所以来了这里,装修风格... | 50 | 1 | 之前 在 会展中心 店 按 过 , 觉得 很 不错 , 说 上 梅林 也 有 一家 店 , ... | 1 |
三、讨论和不足
- 模型没调参
- 没有交叉验证