磐创AI分享
作者|kajal56
编译|Flin
来源|analyticsvidhya
概述
我们今天生活在一个数字世界中。从一天的开始到我们对所爱的人说“晚安”,我们以视觉、音乐/音频、网络、文本和更多来源的形式消耗大量数据。
今天,我们将探索这些数据来源之一,看看我们是否可以从中获取信息。
由于评论、反馈、文章和许多其他数据收集/发布方式,我们将使用大量可用的“文本”数据。
我们将尝试查看是否可以从给定的文本中捕获“情绪”,但首先,我们将对给定的“文本”数据进行预处理并使其结构化,因为它是非结构化的行形式。我们需要将文本数据转换为结构化格式,因为大多数机器学习算法都使用结构化数据。
在本文中,我们将使用来自“Kaggle”的公开数据。请使用以下链接获取数据。
https://www.kaggle.com/amitkumardas/sentiment-train
这将是一个分类练习,因为该数据集由标记为正面或负面的用户的电影评论组成。
情绪分类
我们刚刚讨论的数据集包含电影评论。每条评论都被标记为正面或负面。数据集包含“文本”和“情绪”字段。这些字段由“制表符”字符分隔。详情请见下文:
**1. text: **描述评论的句子。
2. sentiment:1 或 0。1 代表正面评价,0 代表负面评价。
现在我们将讨论“情绪分类”的完整过程。下面是项目的流程。
加载数据集
使用 panda 的 read_csv() 方法加载数据如下:
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')
train_data = pd.read_csv('sentiment_train.csv')
train_data.head(5)
加载数据的前五条记录如下表所示。
![](http://qiniu.aihubs.net/81570Screenshot from 2021-08-26 11-26-29.png)
由于默认列宽是有限的,因此在获取输出时,上表中的一些文本可能已被截断。这可以通过设置 max_colwidth 参数来增加宽度大小来改变。
列句中的每个记录或示例称为一个文档。使用以下代码打印前五个正面情绪文档。
pd.set_option('max_colwidth',1800)
train_data[train_data.label == 1][0:5]
第五个正面情绪。情绪值为 1 表示积极情绪
![](http://qiniu.aihubs.net/57162Screenshot from 2021-08-26 11-27-07.png)
要打印前五个负面情绪文档,请使用:
train_data[train_data.Sentiment == 1][0:5]
前五种负面情绪。情绪值为 0 表示负面情绪。
![](http://qiniu.aihubs.net/58478Screenshot from 2021-08-26 11-29-45.png)
在下一节中,我们将讨论对文本数据的探索性数据分析。
探索数据集
探索性数据分析可以通过统计评论、正面评论、负面评论等的数量来进行,比如我们可以查看数据集中有多少评论?数据集中的正面和负面情绪评论是否得到很好的体现?使用 info() 方法打印数据帧的元数据。
train_data.info()
![](http://qiniu.aihubs.net/42257Screenshot from 2021-08-26 11-37-46.png)
从输出中,我们可以推断数据集中有 5668 条记录。我们创建了一个计数图来比较正面和负面情绪的数量。
import matplotlib.pyplot as plt
import seaborn as sn
%matplotlib inline
plt.figure(figsize=(6,5))
plt.title("Number of records of positive and negative sentiments")
plot = sn.countplot(x = 'Sentiment', data=train_data)
for p in plot.patches:
plot.annotate(p.get_height(),(p.get_x()+0.1 ,p.get_height()+50))
![](http://qiniu.aihubs.net/89799Screenshot from 2021-08-26 11-44-21.png)
从图中我们可以推断出数据集中总共有5668条记录。在 5668 条记录中,2464 条记录属于负面情绪,3204 条记录属于正面情绪。因此,正面和负面情绪文档在数据集中具有相当相同的表示。
在构建模型之前,文本数据需要预处理以进行特征提取。以下部分将逐步介绍文本预处理技术。
文本预处理
本节将重点介绍如何对文本数据进行预处理。必须使用哪个函数来获得更好的数据集格式,该数据集可以将该模型应用于该文本数据集。
我们有一些技术来完成这个过程。本文仅讨论使用创建计数向量。你可以按照我的另一篇文章了解适用于文本数据集的其他一些预处理技术。
单击此处:https://www.analyticsvidhya.com/blog/2021/08/text-preprocessing-techniques-for-performing-sentiment-analysis/#h2_3
所有向量化器类都将停用词列表作为参数,并在构建字典或特征集时删除停用词。并且这些词不会出现在表示文档的计数向量中。我们将绕过停用词列表创建新的计数向量。
count_vectorizer = CountVectorizer(stop_words= my_stop_words, max_features= 1000)
feature_vector = count_vectorizer.fit(train_data.Text)
train_ds_features = count_vectorizer.transform(train_data.Text)
features = feature_vector.get_feature_names()
features_counts = np.sum(train_ds_features.toarray(), axis = 0)
features_counts = pd.DataFrame(dict(features = features, counts = features_counts))
features_counts.sort_values("counts", ascending= False)[0:15]
可以注意到,停用词已被删除。但我们也注意到另一个问题。许多以多种形式出现。例如,爱与爱。向量化器将这两个词视为分离的词,因此创建了两个分离的特征。但是如果一个词的所有形式都具有相似的含义,我们就只能使用词根作为特征。词干提取和词形还原是两种流行的技术,用于将单词转换为词根。
1.词干:这消除了一个词的屈折形式之间的差异,将每个词减少到它的词根形式。这主要是通过切掉单词的结尾来完成的。流式传输的一个问题是切词可能会导致单词不属于词汇表。PorterStemmer 和 LancasterStemmer 是两种流行的流媒体算法,它们有关于如何截断单词的规则。
2.词形还原:这考虑了单词的形态分析。它使用语言词典将单词转换为词根。例如,词干无法区分人与人之间的差异,而词形还原可以将这些词恢复为原始词。
from nltk.stem.snowball import PorterStemmer
stemmer = PorterStemmer()
analyzer = CountVectorizer().build_analyzer()
def stemmed_words(doc):
stemmed_words = [stemmer.stem(w) for w in analyzer(doc)]
non_stop_words = [word for word in stemmed_words if not in my_stop_words]
return non_stop_words
在创建计数向量之前,CountVectorizer 采用自定义分析器进行流传输并停止删除单词。因此,自定义函数 stemmed_words() 作为分析器传递。
count_vectorizer = CountVectorizer(stop_words= my_stop_words, max_features= 1000)
feature_vector = count_vectorizer.fit(train_data.Text)
train_ds_features = count_vectorizer.transform(train_data.Text)
features = feature_vector.get_feature_names()
features_counts = np.sum(train_ds_features.toarray(), axis = 0)
features_counts = pd.DataFrame(dict(features = features, counts = features_counts))
features_counts.sort_values("counts", ascending= False)[0:15]
按降序打印前 15 个单词及其计数。
![](http://qiniu.aihubs.net/98955Screenshot from 2021-08-28 09-40-27.png)
可以注意到,love、loved、awesome这些词都源于词根。
预处理完成后,继续构建模型。
建立情感分类模型
我们将建立不同的模型来对情绪进行分类。
现在我们将一一讨论。
先来讨论朴素贝叶斯分类器
朴素贝叶斯分类器广泛用于自然语言处理,并被证明能提供更好的结果。它适用于贝叶定理的概念。
假设我们想预测一个文档的概率是否为正,因为该文档包含一个单词 awesome。如果给定它是正面情绪的文档中出现 awesome 单词的概率乘以文档正面的概率,则可以计算出这个值。
P(doc = +ve | word = awesome) = P(word = awesome | doc = +ve) * P(doc = +ve)
情感的后验概率是从它包含的所有单词的先验概率计算出来的。假设是文档中出现的单词被认为是独立的,它们不会相互影响。
所以,如果文档包含 N 个单词,单词表示为 w1, w2, w3………wn ,那么
P(doc = +ve | word = w1, w2, w3………wn) =
sklearn.naive_bayes 提供了一个 BernoulliNB 类,它是一个用于多元 BernoulliNB 模型的朴素贝叶斯分类器。BernoulliNB 是为二元特征设计的,这里就是这种情况。
使用朴素贝叶斯模型进行情感分类的步骤如下:
我们将在以下小节中讨论这些。
使用以下代码将数据集拆分为 70:30 的比例,以创建训练和测试数据集。
from sklearn.model_selection import train_test_split
train_x, test_x, train_y, test_y = train_test_split(train_ds_features, train_data.Sentiment,
test_size = 0.3, random_state = 42)
使用训练集构建朴素贝叶斯模型。
from sklearn.naive_bayes import BernoulliNB
nb_clf = BernoulliNB()
nb_clf.fit(train_x.toarray(), train_y)
根据朴素贝叶概率计算,预测的类别将是具有较高概率的类别。预测的测试数据集的使用predict()方法的意见。
test_ds_predicted = nb_clf.predict(test_x.toarray())
让我们打印分类报告。
from sklearn import metrics
print(metrics.classification_report(test_y,test_ds_predicted))
![](http://qiniu.aihubs.net/66771Screenshot from 2021-08-27 13-41-53.png)
该模型以非常高的准确度进行分类。识别正面和负面情绪文档的平均准确率和召回率均约为 98%。让我们绘制混淆矩阵。
cm = metrics.confusion_matrix(test_y, test_ds_predicted)
sn.heatmap(cm, annot=True, fmt = '.2f')
在混淆矩阵中,行表示测试集中正面和负面文档的实际数量,而列表示模型预测的内容。标签 1 表示正面情绪,标签 0 表示负面情绪。
![](http://qiniu.aihubs.net/78871Screenshot from 2021-08-27 13-46-02.png)
根据模型预测,只有 13 个实例被错误地归类为负面情绪文档,只有 26 个负面情绪文档被错误地归类为正面情绪文档。其余均已正确分类。
下一节将讨论 TD-IFD 向量化模型。
**TF-IDF矢量化器 **
TfidfVectorizer 用于创建 TF Vectorizer 和 TF-IDF Vectorizer。使用 _idf 创建 TF-IDF 向量需要一个参数。如果使用 _idf 设置为 false,它将只创建 TF 向量,如果设置为 True,它将创建 TF-IDF 向量。
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vectorizer = TfidfVectorizer(analyzer = stemmed_words, max_features = 1000)
feature_vector = tfidf_vectorizer.fit(train_data.Text)
train_ds_features = tfidf_vectorizer.transform(train_data.Text)
features = feature_vector.get_feature_names()
Tf-IDF 是连续值,可以假设这些与每个类相关联的连续值按照高斯分布进行分布。所以高斯朴素贝叶斯可以用来对这些文档进行分类。我们将 GaussianNB,它实现了用于分类的 Gaussian Naive_bayes 算法。
from sklearn.naive_bayes import GaussianNB
train_x, test_x, train_y, test_y = train_test_split(train_ds_features, train_data.Sentiment,
test_size = 0.3, random_state = 42)
nb_clf = GaussianNB()
nb_clf.fit(train_x.toarray(), train_y)
test_ds_predicted = nb_clf.predict(test_x.toarray())
print(metrics.classification_report(test_y,test_ds_predicted))
![](http://qiniu.aihubs.net/77159Screenshot from 2021-08-27 14-19-38.png)
cm = metrics.confusion_matrix(test_y, test_ds_predicted)
sn.heatmap(cm, annot=True, fmt = '.2f')
![](http://qiniu.aihubs.net/66931Screenshot from 2021-08-27 14-20-32.png)
精确率和召回率似乎几乎相同。在这个例子中准确度非常高,因为数据集是干净的并且经过精心策划。但在现实世界中可能并非如此。
结论
在本文中,文本数据是非结构化数据,在应用模型之前需要进行大量预处理。朴素贝叶斯分类模型是最广泛使用的文本分类算法。下一篇文章将讨论使用少量技术(例如使用 N-Grams)进行文本分析的一些挑战。