最近闲来无事,看了 王树义老师 的一篇文章 《如何用Python和机器学习训练中文文本情感分类模型》,跟着步骤做了一个demo,此demo是爬取了美团用户的评论,对评论进行情感分析,收获很大,特此做下了笔记。
首先导入库
import pandas as pd
import numpy as np
from pandas import DataFrame, Series
读取评论数据,数据在 这里
data = pd.read_csv("data.csv", encoding='GB18030')
data
根据评分,使用lambda
匿名函数,把评分>3的,取值1,当作正向情感,评分<3的,取值0,当作负向情感
def make_label(df):
df["sentiment"] = df["star"].apply(lambda x: 1 if x > 3 else 0)
调用方法,并查看结果
make_label(data)
data
特征、标签分开赋值:
X = data[["comment"]]
y = data.sentiment
导入 jieba
分词库,创建分词函数,将评论拆分,并用空格连接
通过 apply
调用函数,并新增列,填充值:
import jieba
def chinese_word_cut(mytext):
return " ".join(jieba.cut(mytext))
X["cuted_comment"] = X.comment.apply(chinese_word_cut)
接下来要将一团的数据,拆分成训练数据集、测试数据集
从sklearn.model_selection
导入数据拆分函数train_test_split
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
查看数据集形状:
X_train.shape
可知道,train_test_split
在默认模式下,训练数据集、测试数据集比例是3:1。
接下来要处理中文停用词,可使用第三方停用词表,能在 这个GitHub上找到
创建停词函数,将停用词转成列表形式返回:
def get_custom_stopword(stop_word_file):
with open(stop_word_file) as f:
stop_word = f.read()
stop_word_list = stop_word.split("/n")
custom_stopword = [i for i in stop_word_list]
return custom_stopword
stopwords = get_custom_stopword("哈工大停用词表.txt")
导入 CountVectorizer
函数,将中文词语向量化:
from sklearn.feature_extraction.text import CountVectorizer
默认参数向量化
vect = CountVectorizer()
term_matrix = DataFrame(vect.fit_transform(X_train.cuted_comment).toarray(), columns=vect.get_feature_names())
向量化后的数据集
term_matrix.shape
(1500, 7305)
发现有特别多的数字存在,这些数字并不具有特征性,若是不过滤,会影响后面模型训练的效果
将一部分特征向量过滤,
给CountVectorizer
添加参数,并重新对数据集向量化:
max_df = 0.8 # 在超过这一比例的文档中出现的关键词(过于平凡),去除掉。
min_df = 3 # 在低于这一数量的文档中出现的关键词(过于独特),去除掉。
vect = CountVectorizer(max_df = max_df,
min_df = min_df,
token_pattern=u'(?u)\\b[^\\d\\W]\\w+\\b',
stop_words=frozenset(stopwords))
term_matrix = DataFrame(vect.fit_transform(X_train.cuted_comment).toarray(), columns=vect.get_feature_names())
向量化后的数据集
term_matrix.shape
(1500, 1972)
过滤了很多词汇,好棒!
训练集已向量化完成,现在使用此特征矩阵训练模型
导入 朴素贝叶斯
函数,建立分类模型
from sklearn.naive_bayes import MultinomialNB
nb = MultinomialNB()
注意,我们的处理数据流程是:
1、特征向量化
2、贝叶斯分类
如果每修改一次参数,就要重新运行以上函数,会十分头疼
sklearn
提供了一个管道pipeline
功能,能将顺序工作连接起来
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(vect, nb)
pipe
现在我们就可以把pipe
当成一个完整的模型来使用了。
将未特征向量化的数据输入,验证模型的准确率:
from sklearn.model_selection import cross_val_score
cross_val_score(pipe, X_train, y_train, cv=5, scoring='accuracy').mean()
得分:
0.8333673633410742
到此为止,模型已经初步搭建好了。【鼓掌】
但是我们用的都是训练过的数据集来测试的,准确率真的有这么高吗,来,我们进行下一步测试。
先用训练集拟合数据:
pipe.fit(X_train.cuted_comment, y_train)
测试集预测结果:
y_pred = pipe.predict(x_test.cuted_comment)
使用 metrics
测度工具查看评分
from sklearn import metrics
metrics.accuracy_score(y_test, y_pred)
评分:
0.866
结果显示,我们的模型对未曾见过的数据,预测的精确度达86.6%。
混淆矩阵验证
metrics.confusion_matrix(y_test, y_pred)
结果
array([[200, 37],
[ 30, 233]], dtype=int64)
混淆矩阵中的数字从上到下,从左到右分别表示:
可见我们的模型性能还是挺不错的。
下面我们来用 snowNLP
来做对比:
from snownlp import SnowNLP
def get_sentiment(text):
return SnowNLP(text).sentiments
使用测试集跑一遍:
y_pred_snow = X_test.comment.apply(get_sentiment)
结果:
snowNLP
返回的结果是0-1之间的数,而不是0、1,因此我们需要将数据转换一下,大于0.5为1,小于0.5为0。
y_pred_snow_norm = y_pred_snow.apply(lambda x: 1 if x>0.5 else 0)
metrics.accuracy_score(y_test, y_pred_snow_norm)
0.77
en,比我们的模型差点。。
混淆矩阵:
metrics.confusion_matrix(y_test, y_pred_snow_norm)
array([[189, 48],
[ 67, 196]], dtype=int64)
en,确实比我们的模型差点。。
以上。