目录
自然语言处理(Natural Language Processing,简称NLP),是为各类企业及开发者提供的用于文本分析及挖掘的核心工具,旨在帮助用户高效的处理文本,已经广泛应用在电商、文娱、司法、公安、金融、医疗、电力等行业客户的多项业务中,取得了良好的效果。
1、项目背景
任何行业领域,用户对产品的评价都显得尤为重要。通过用户评论,可以对用户情感倾向进行判定。
例如,目前最为普遍的网购行为:对于用户来说,参考评论可以做出更优的购买决策;对于商家来说,对商品评论按照情感倾向进行分类,并通过文本聚类得到普遍提及的商品优缺点,可以进一步改良产品。
本案例主要讨论如何对商品评论进行情感倾向判定。下图为某电商平台上针对某款手机的部分评论:
2、数据集
这份某款手机的商品评论信息数据集,包含2个属性,共计8187个样本。
使用Pandas
中的read_excel
函数读取xls
格式的数据集文件,注意文件的编码设置为gb18030
,代码如下所示:
-
import pandas as pd
-
#读入数据集
-
data = pd.read_excel("data.xls", encoding='gb18030')
-
print(data.head())
读取数据集效果(部分)如下所示:
查看数据集的相关信息,包括行列数,列名,以及各个类别的样本数,实现代码如下所示:
-
# 数据集的大小
-
print(data.shape)
-
# 数据集的列名
-
print(data.columns.values)
-
# 不同类别数据记录的统计
-
print(data['Class'].value_counts())
效果如下所示
-
(8186, 2)
-
array([u'Comment', u'Class'], dtype=object)
-
1 3042
-
-1 2657
-
0 2487
-
Name: Class, dtype: int64
3、数据预处理
现在,我们要将Comment
列的文本信息,转化成数值矩阵表示,也就是将文本映射到特征空间。
首先,通过jieba
,使用HMM
模型,对文本进行中文分词,实现代码如下所示:
-
# 导入中文分词库jieba
-
import jieba
-
import numpy as np
接下来,对数据集的每个样本的文本进行中文分词,如遇到缺失值,使用“还行、一般吧”进行填充,实现代码如下所示:
-
cutted = []
-
for row in data.values:
-
try:
-
raw_words = (" ".join(jieba.cut(row[0])))
-
cutted.append(raw_words)
-
except AttributeError:
-
print row[0]
-
cutted.append(u"还行 一般吧")
-
cutted_array = np.array(cutted)
-
# 生成新数据文件,Comment字段为分词后的内容
-
data_cutted = pd.DataFrame({
-
'Comment': cutted_array,
-
'Class': data['Class']
-
})
读取并查看预处理后的数据,实现代码如下所示:
print(data_cutted.head())
数据集效果(部分)如下所示:
为了更直观地观察词频高的词语,我们使用第三方库wordcloud
进行文本的可视化,导入库实现代码如下所示:
-
# 导入第三方库wordcloud
-
from wordcloud import WordCloud
-
import matplotlib.pyplot as plt
针对好评,中评和差评的文本,建立WordCloud
对象,绘制词云,好评词云可视化实现代码如下所示:
-
# 好评
-
wc = WordCloud(font_path='Courier.ttf')
-
wc.generate(''.join(data_cutted['Comment'][data_cutted['Class'] == 1]))
-
plt.axis('off')
-
plt.imshow(wc)
-
plt.show()
好评词云效果如下所示:
中评词云可视化实现代码如下所示:
-
# 中评
-
wc = WordCloud(font_path='Courier.ttf')
-
wc.generate(''.join(data_cutted['Comment'][data_cutted['Class'] == 0]))
-
plt.axis('off')
-
plt.imshow(wc)
-
plt.show()
中评词云效果如下所示:
差评词云可视化实现代码如下所示:
-
# 差评
-
wc = WordCloud(font_path='Courier.ttf')
-
wc.generate(''.join(data_cutted['Comment'][data_cutted['Class'] == -1]))
-
plt.axis('off')
-
plt.imshow(wc)
-
plt.show()
差评词云效果如下所示:
从词云展现的词频统计图来看,"手机","就是","屏幕","收到"等词对于区分毫无帮助而且会造成偏差。因此,需要把这些对区分类没有意义的词语筛选出来,放到停用词文件stopwords.txt
中。实现代码如下所示:
-
# 读入停用词文件
-
import codecs
-
with codecs.open('stopwords.txt', 'r', encoding='utf-8') as f:
-
stopwords = [item.strip() for item in f]
-
for item in stopwords[0:200]:
-
print(item,)
输出停用词效果如下所示:
使用jieba
库的extract_tags
函数,统计好评,中评,差评文本中的TOP20
关键词。
-
#设定停用词文件,在统计关键词的时候,过滤停用词
-
import jieba.analyse
-
jieba.analyse.set_stop_words('stopwords.txt')
好评关键词分析,实现代码如下所示:
-
# 好评关键词
-
keywords_pos = jieba.analyse.extract_tags(''.join(data_cutted['Comment']
-
[data_cutted['Class'] == 1]), topK=20)
-
for item in keywords_pos:
-
print(item,)
好评关键词TOP20
如下所示:
不错 正品 赠品 五分 发货 东西 满意 机子 喜欢 收到 很漂亮 充电 好评 很快 卖家 速度 评价 流畅 快递 物流
中评关键词分析,实现代码如下所示:
-
#中评关键词
-
keywords_med = jieba.analyse.extract_tags(''.join(data_cutted['Comment'][data_cutted
-
['Class'] == 0]), topK=20)
-
for item in keywords_med:
-
print(item,)
中评关键词TOP20
如下所示:
充电 不错 发热 外观 感觉 电池 机子 问题 赠品 有点 无线 发烫 换货 软件 快递 安卓 内存 退货 知道 售后
差评关键词分析,实现代码如下所示:
-
#差评关键词
-
keywords_neg = jieba.analyse.extract_tags(''.join(data_cutted['Comment'][data_cutted
-
['Class'] == -1]), topK=20)
-
for item in keywords_neg:
-
print(item,)
差评关键词TOP20
如下所示:
差评 售后 垃圾 赠品 退货 问题 换货 充电 降价 发票 充电器 东西 刚买 发热 无线 机子 死机 收到 质量 15
经过以上步骤的处理,整个数据集的预处理工作“告一段落”。在中文文本分析和情感分析的工作中,数据预处理的内容主要是分词。只有经过分词处理后的文本数据集才可以进行下一步的向量化操作,满足输入模型的条件。
4、基于SVM的情感分类模型
经过分词之后的文本数据集要先进行向量化之后才能输入到分类模型中进行运算。
我们使用sklearn
库实现向量化方法,去掉停用词,并将其通过tf
,tf-idf
映射到特征空间。
其中,tftf为词频,即分词后每个词项在该条评论中出现的次数;dfdf为出现该词项评论数目;NN为评论总数,使用对数来适当抑制tftf和dfdf值的影响。
我们使用sklearn
库中的函数直接实现SVM算法。在这里,我们选取以下形式的SVM模型参与运算。
为了方便,创建文本情感分析类CommentClassifier
,来实现建模过程:
__init__
为类的初始化函数,输入参数classifier_type
和vector_type
,分别代表分类模型的类型和向量化方法的类型。fit()
函数,来实现向量化与模型建立的过程。
实现代码如下所示:
-
# 实现向量化方法
-
from sklearn.feature_extraction.text import TfidfVectorizer
-
from sklearn.feature_extraction.text import CountVectorizer
-
#实现svm和贝叶斯模型
-
from sklearn.svm import SVC
-
from sklearn.svm import LinearSVC
-
from sklearn.linear_model import SGDClassifier
-
# 实现交叉验证
-
from sklearn.cross_validation import train_test_split
-
from sklearn.cross_validation import cross_val_score
-
# 实现评价指标
-
from sklearn import metrics
-
# 文本情感分类的类:CommentClassifier
-
class CommentClassifier:
-
def __init__(self, classifier_type, vector_type):
-
self.classifier_type = classifier_type #分类器类型:支持向量机或贝叶斯分类
-
self.vector_type = vector_type #文本向量化模型:0\1模型,TF模型,
-
TF-IDF模型
-
def fit(self, train_x, train_y, max_df):
-
list_text = list(train_x)
-
#向量化方法:0 - 0/1,1 - TF,2 - TF-IDF
-
if self.vector_type == 0:
-
self.vectorizer = CountVectorizer(max_df, stop_words = stopwords,
-
ngram_range=(1, 3)).fit(list_text)
-
elif self.vector_type == 1:
-
self.vectorizer = TfidfVectorizer(max_df, stop_words = stopwords,
-
ngram_range=(1, 3), use_idf=False).fit(list_text)
-
else:
-
self.vectorizer = TfidfVectorizer(max_df, stop_words = stopwords,
-
ngram_range=(1, 3)).fit(list_text)
-
self.array_trainx = self.vectorizer.transform(list_text)
-
self.array_trainy = train_y
-
#分类模型选择:1 - SVC,2 - LinearSVC,3 - SGDClassifier,三种SVM模型
-
if self.classifier_type == 1:
-
self.model = SVC(kernel='linear', gamma=10 ** -5, C=1).fit
-
(self.array_trainx, self.array_trainy)
-
elif self.classifier_type == 2:
-
self.model = LinearSVC().fit(self.array_trainx, self.array_trainy)
-
else:
-
self.model = SGDClassifier().fit(self.array_trainx, self.array_trainy)
-
def predict_value(self, test_x):
-
list_text = list(test_x)
-
self.array_testx = self.vectorizer.transform(list_text)
-
array_predict = self.model.predict(self.array_testx)
-
return array_predict
-
def predict_proba(self, test_x):
-
list_text = list(test_x)
-
self.array_testx = self.vectorizer.transform(list_text)
-
array_score = self.model.predict_proba(self.array_testx)
-
return array_score
- 使用
train_test_split()
函数划分训练集和测试集。训练集:80%;测试集:20%。 - 建立
classifier_type
和vector_type
两个参数的取值列表,来表示选择的向量化方法以及分类模型 - 输出每种向量化方法和分类模型的组合所对应的分类评价结果,内容包括混淆矩阵以及含
Precision
、Recall
和F1-score
三个指标的评分矩阵
实现代码如下所示:
-
#划分训练集,测试集
-
train_x, test_x, train_y, test_y = train_test_split(data_cutted['Comment'].ravel().
-
astype('U'), data_cutted['Class'].ravel(),
-
test_size=0.2, random_state=4)
-
classifier_list = [1,2,3]
-
vector_list = [0,1,2]
-
for classifier_type in classifier_list:
-
for vector_type in vector_list:
-
commentCls = CommentClassifier(classifier_type, vector_type)
-
#max_df 设置为0.98
-
commentCls.fit(train_x, train_y, 0.98)
-
if classifier_type == 0:
-
value_result = commentCls.predict_value(test_x)
-
proba_result = commentCls.predict_proba(test_x)
-
print(classifier_type,vector_type)
-
print('classification report')
-
print(metrics.classification_report(test_y, value_result, labels=
-
[-1, 0, 1]))
-
print('confusion matrix')
-
print(metrics.confusion_matrix(test_y, value_result, labels=
-
[-1, 0, 1]))
-
else:
-
value_result = commentCls.predict_value(test_x)
-
print(classifier_type,vector_type)
-
print('classification report')
-
print(metrics.classification_report(test_y, value_result, labels=
-
[-1, 0, 1]))
-
print('confusion matrix')
-
print(metrics.confusion_matrix(test_y, value_result, labels=[-1, 0, 1]))
。。。。。。。。。。。。。。。。。
版权原因,完整文章,请参考如下:自然语言处理:网购商品评论情感判定