作者|Kiprono Elijah Koech
编译|VK
来源|Towards Data Science
在本文中,我们将讨论一个分类问题,该问题涉及到将评论分为正面或负面。这里使用的评论是客户在ABC服务上所做的评论。
数据收集和预处理
在这个项目中使用的数据是从网上爬来的,数据清理在这个Notebook上完成:https://github.com/kipronokoe...
在我们抓取数据后被保存到一个.txt文件中,下面是一行文件的例子(代表一个数据点)
{'socialShareUrl': 'https://www.abc.com/reviews/5ed0251025e5d20a88a2057d', 'businessUnitId': '5090eace00006400051ded85', 'businessUnitDisplayName': 'ABC', 'consumerId': '5ed0250fdfdf8632f9ee7ab6', 'consumerName': 'May', 'reviewId': '5ed0251025e5d20a88a2057d', 'reviewHeader': 'Wow - Great Service', 'reviewBody': 'Wow. Great Service with no issues. Money was available same day in no time.', 'stars': 5}
数据点是一个字典,我们对reviewBody和stars感兴趣。
我们将把评论分类如下
1 and 2 - Negative
3 - Neutral
4 and 5 - Positive
在收集数据时,网站上有36456条评论。数据高度不平衡:94%的评论是正面的,4%是负面的,2%是中性的。在这个项目中,我们将在不平衡的数据和平衡的数据上拟合不同的Sklearn模型(我们去掉一些正面评论,这样我们就有相同数量的正面和负面评论。)
下图显示了数据的组成:
在上图中,我们可以看到数据是高度不平衡的。
让我们从导入必要的包开始,并定义将用于对给定的评论进行分类的类Review
#导入包
import numpy as np
import random
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.metrics import f1_score #f1分数,一种评价指标
import ast #将字符串转换为字典
from IPython.display import clear_output
from sklearn import svm #支持向量机分类器
from sklearn.metrics import confusion_matrix
from sklearn.linear_model import LogisticRegression #导入 logistic regression
from sklearn.tree import DecisionTreeClassifier #导入 Decision tree
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
import pandas as pd
import seaborn as sb
# 将评论分为正面、负面或中性
class Review:
def __init__(self, text, score):
self.text = text
self.score = score
self.sentiment = self.get_sentiment()
def get_sentiment(self):
if self.score <= 2:
return "NEGATIVE"
elif self.score == 3:
return "NEUTRAL"
else: #4或5分
return "POSITIVE"
在这里,我们将加载数据并使用Review类将评论分类为正面、反面或中性
# 大部分清理是在数据web爬取期间完成的
# Notebook 链接
# https://github.com/kipronokoech/Reviews-Classification/blob/master/data_collection.ipynb
reviews = []
with open("./data/reviews.txt") as fp:
for index,line in enumerate(fp):
# 转换为字典
review = ast.literal_eval(line)
#对评论进行分类并将其附加到reviews中
reviews.append(Review(review['reviewBody'], review['stars']))
# 打印出reviews[0]的情绪类别和文本
print(reviews[0].text)
print(reviews[0].sentiment)
Wow. Great Service with no issues. Money was available same day in no time.
POSITIVE
将数据拆分为训练集和测试集
# 70%用于训练,30%用于测试
training, test = train_test_split(reviews, test_size=0.30, random_state=42)
# 定义X和Y
train_x,train_y = [x.text for x in training],[x.sentiment for x in training]
test_x,test_y = [x.text for x in test],[x.sentiment for x in test]
print("Size of train set: ",len(training))
print("Size of train set: ",len(test))
Size of train set: 25519
Size of train set: 10937
在我们继续下一步之前,我们需要理解词袋的概念。
词袋
正如我们所知,一台计算机只理解数字,因此我们需要使用词袋模型将我们收到的评论信息转换成一个数字列表。
词袋是一种文本表示形式。它包括两个方面:已知单词的词汇与已知单词存在程度的度量。
词袋模型是一种用于文档分类的支持模型,其中每个词的出现频率作为训练分类器的特征。
例子:
考虑这两个评论
- Excellent Services by the ABC remit team.Recommend.
- Bad Services. Transaction delayed for three days.Don’t recommend.
从以上两句话中,我们可以得出以下词典
[Excellent, Services, by, the, ABC, remit, team, recommend, bad, transaction, delayed, for, three, days, don’t]
我们现在将这个字典标记化以生成以下两个数据点,这些数据点现在可以用来训练分类器
在python中,标记化的实现如下
# 导入用于向量化的库
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
# sklearn上的向量化——简单的例子
corpus = [
"Excellent Services by the ABC remit team.Recommend.",
"Bad Services. Transaction delayed for three days.Don't recommend."]
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(corpus)
#print(X) #这是一个矩阵
print(vectorizer.get_feature_names()) # 字典
print(X.toarray())#显然是一个矩阵,每一行都是每个句子的标记值
['abc', 'bad', 'by', 'days', 'delayed', 'don', 'excellent', 'for', 'recommend', 'remit', 'services', 'team', 'the', 'three', 'transaction']
[[1 0 1 0 0 0 1 0 1 1 1 1 1 0 0]
[0 1 0 1 1 1 0 1 1 0 1 0 0 1 1]]
现在我们已经理解了词袋的概念,现在让我们将这些知识应用到我们的训练和测试中
vectorizer = TfidfVectorizer()
train_x_vectors = vectorizer.fit_transform(train_x)
test_x_vectors = vectorizer.transform(test_x)
在不平衡数据中训练模型
现在,我们拥有了向量,我们可以用来拟合模型,我们可以这样做
支持向量机
#训练支持向量机分类器
clf_svm = svm.SVC(kernel='linear')
clf_svm.fit(train_x_vectors, train_y)
#基于SVM的随机预测
i = np.random.randint(0,len(test_x))
print("Review Message: ",test_x[i])
print("Actual: ",test_y[i])
print("Prediction: ",clf_svm.predict(test_x_vectors[i]))
#支持向量机的混淆矩阵——你可以有其他分类器的混淆矩阵
labels = ["NEGATIVE","NEUTRAL","POSITIVE"]
pred_svm = clf_svm.predict(test_x_vectors)
cm =confusion_matrix(test_y,pred_svm)
df_cm = pd.DataFrame(cm, index=labels, columns=labels)
sb.heatmap(df_cm, annot=True, fmt='d')
plt.title("Confusion matrix from SVM [Imbalanced]")
plt.savefig("./plots/confusion.png")
Review Message: easy efficient first class
Actual: POSITIVE
Prediction: ['POSITIVE']
训练的其他模型包括随机森林、朴素贝叶斯、决策树和Logistic回归。
完整代码的链接:https://github.com/kipronokoe...
基于不平衡数据的模型性能评估
- 准确度
利用准确度对模型进行了评估,结果如下
我们得到了90%的准确率,是正确还是有问题?答案是,出了点问题。
数据是不平衡的,使用准确度作为评估指标不是一个好主意。以下是各类别的分布情况
----------TRAIN SET ---------------
Positive reviews on train set: 23961 (93.89%)
Negative reviews on train set: 1055 (4.13%)
Neutral reviews on train set: 503 (1.97%)
----------TEST SET ---------------
Positive reviews on test set: 10225 (93.48%)
Negative reviews on test set: 499 (4.56%)
Neutral reviews on test set: 213 (1.95%)
如果分类器正确地预测了测试集中所有的正面评价,而没有预测到负面和中性评论,会发生什么?该分类器的准确率可达93.48%!!!!!!
这意味着我们的模型将是93.48%的准确率,我们会认为模型是好的,但实际上,模型“只知道”如何预测一类(正面评价)。事实上,根据我们的结果,我们的支持向量机预测根本没有中性评论
为了进一步理解这个问题,让我们引入另一个指标:F1分数,并用它来评估我们的模型。
- F1分数
F1分数是精确和召回率的调和平均值。
精确性和召回率衡量模型正确区分正面案例和负面案例的程度。
当我们根据这个指标评估我们的模型时,结果如下
从图中,我们现在知道这些模型在对正面评论进行分类时非常好,而在预测负面评论和中性评论方面则很差。
使用平衡数据
作为平衡数据的一种方法,我们决定随机删除一些正面评论,以便我们在训练模型时使用均匀分布的评论。这一次,我们正在训练1055个正面评论和1055个负面评论的模型。我们放弃中性评论。
(你也可以考虑使用过采样技术来解决数据不平衡的问题)
在训练了模型之后,我们得到了以下结果
支持向量机的最佳结果是88.9%的准确率,在检查F1分数(如下)后,我们现在可以意识到模型预测负面评价和正面评价一样好。
如果我们看一下显示支持向量机结果的混淆矩阵,我们会注意到该模型在预测两个类方面都很好
在这里找到完整的代码:https://github.com/kipronokoe...
结论
在完成这个项目后,我希望你能够了解到:
- 在不平衡的数据上拟合一个或多个模型可能(在大多数情况下确实如此)会导致不良结果。
- 在处理不平衡数据时,准确度不是一个好的衡量标准。
- 大部分工作是在预处理阶段完成的。
感谢阅读
原文链接:https://towardsdatascience.co...
欢迎关注磐创AI博客站:
http://panchuang.net/
sklearn机器学习中文官方文档:
http://sklearn123.com/
欢迎关注磐创博客资源汇总站:
http://docs.panchuang.net/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。