【入门】Twitter情感分析全面分析指南(含代码)

2018 年 8 月 1 日 论智
来源:Analytics Vidhya
编译:Bot

编者按:自然语言处理(NLP)是数据科学研究的一个温床,它最常见的应用之一是情感分析。从民意调查到指定整个营销策略,现在,这种技术已经完全重塑了企业的工作方式,这也是为什么每个数据科学家都要对它有所了解的原因之一。

本文将围绕以twitter为代表英语文本进行分析,在文中,我们会逐步介绍常规情感分析所需的一系列步骤:从数据预处理开始,到探索文本数据,再到结合上下文产生理解,然后从数据中提取数字特征,并最终用这些特征集来训练模型,使它具备识别情感的能力。

理解任务目标

实践是检验真理的唯一标准,它同样也是学习的一个好方法。为了让读者更贴近教程,这里我们选用Analytics Vidhya上的一个竞赛任务:Twitter情感分析。里面包含下文使用的数据集。

在开始任务前,我们先来读读任务描述,理解任务目标:

这项任务的目的是检测推文中的仇恨言论。为了简单起见,这里我们只把包含种族主义和性别歧视的推文视为仇恨言论,因此,任务目标是从给定推文中分类出包含种族主义、性别歧视观点的推文。

任务提供的训练样本有其相应的分类标签,其中标签“1”表示推文包含种族主义/性别歧视观点,标签“2”则是不包含。我们的目标是用训练集训练模型,让它在测试集上准确预测推文标签。

推文预处理和清洗

当我们进行探索时,电脑中的新问题就像现实生活中的陌生环境,我们对它一无所知,但它却处处包含我们所需的信息。

上图是两个办公室,一个凌乱不堪,一个整洁有序,你觉得自己在哪儿能更快找到文档呢?这不是我们自己的房间,所以毫无疑问的,第二个。同理,如果我们的数据能以结构化的格式排列,模型也能更容易从中找到正确信息。

数据预处理是我们面对任何问题时必不可少的一步,在这个任务中,我们要做的是清除和推文情感不怎么相关的各种噪声,比如标点符号、特殊字符、数字和表示语气的词。这些内容在文本上下文中没有太大权重,再加上我们之后要提取数字特征,去除这些内容有助于之后获得质量更高的特征空间。

首先,我们检查数据,并加载必要的库:

  
  
    
  1. import re

  2. import pandas as pd

  3. import numpy as np

  4. import matplotlib.pyplot as plt

  5. import seaborn as sns

  6. import string

  7. import nltk

  8. import warnings

  9. warnings.filterwarnings("ignore", category=DeprecationWarning)

  10. %matplotlib inline

  
  
    
  1. train  = pd.read_csv('train_E6oV3lV.csv')

  2. test = pd.read_csv('test_tweets_anuFYb8.csv')

记得检查一下训练集的前几行,看看有没有问题:

  
  
    
  1. train.head()

可以看到,数据一共有三列:id、标签和推文文本。标签是二进制目标变量,而推文包含我们将清洗和预处理的文字。以下是数据预处理的几个要求:

  • 为了照顾隐私,数据集把用户名一致标记为@user,这个句柄对推文内容毫无用处,需要删除。

  • 文中的标点符号、特殊字符和数字也没有多大含义,也起不到区分作用,需要删除。

  • 对于情感分析,一些非常短的词也没有实际价值,比如“pdx”“his”“all”,需要删除。

  • 一旦我们执行了上述三个步骤,我们就可以将每个推文分成单个单词或词例,这是任何NLP任务中必须的步骤。

  • 第4条推文中出现了一个“love”,考虑到其他推文中可能会出现类似的“loves”“loving”“lovable”,我们可以把它们都缩成词根“love”,减少数据中唯一单词的总数,同时也不会丢失大量信息。

1. 删除推文句柄@user

如上所述,推文包含许多Twitter句柄(@user),我们需要删掉它们。为了方便起见,这个步骤可以结合训练集和测试集,把两边的句柄同时删掉,防止之后进行重复操作。

  
  
    
  1. combi = train.append(test, ignore_index=True)

下面是我们定义的函数,用于删除推文中不需要的内容。它有两个参数,一个是原始文本字符串,另一个是要从字符串中删去的内容:

  
  
    
  1. def remove_pattern(input_txt, pattern):

  2.    r = re.findall(pattern, input_txt)

  3.    for i in r:

  4.        input_txt = re.sub(i, '', input_txt)

  5.    return input_txt

接着,我们可以创建一个新的列tidy_tweet,用它存储清洗后的推文:

  
  
    
  1. #remove twitter handles(@user)

  2. combi [ 'tidy_tweet' ] = np.vectorize(remove_pattern)(combi [ 'tweet' ],“@ [\ w] *” )

2. 删除标点符号、数字和特殊字符

之前提到了,标点符号、数字和特殊字符也没有多大用处,所以在删除句柄时,我们可以一并把它们处理了:

  
  
    
  1. # remove special characters, numbers, punctuations

  2. combi['tidy_tweet'] = combi['tidy_tweet'].str.replace("[^a-zA-Z#]", " ")

3. 删除短词

同理,一些过短的单词也是我们的删除目标,但执行这一步时我们要小心,因为有些包含意义的单词本身也很短。经过综合评判,最后我们把长度为3及以下的词语统统删去:

  
  
    
  1. combi['tidy_tweet'] = combi['tidy_tweet'].apply(lambda x: ' '.join([w for w in x.split() if len(w)>3]))

处理完毕后,我们需要回过头来重新检查数据集的前几行,看看有没有错误。

  
  
    
  1. combi.head()

如上图所示,我们可以明显看出原始推文和tidy_tweet之间的区别,后者删除了大量不必要的噪声,只保留重要单词。

4. 分词

现在,我们已经对数据完成清洗,接下来就是在本文中标记出单独的单词或词例,所谓分词就是把文本切分成一个个单独的词的过程。

  
  
    
  1. tokenized_tweet = combi['tidy_tweet'].apply(lambda x: x.split())

  2. tokenized_tweet.head()

5. 提取词干

词干是词的一部分,由词根和词缀构成,放在我们的任务中,就是把英文单词的后缀“ing”“ly”“es”“s”等剥离。

  
  
    
  1. from nltk.stem.porter import *

  2. stemmer = PorterStemmer()

  3. tokenized_tweet = tokenized_tweet.apply(lambda x: [stemmer.stem(i) for i in x]) # stemming

  4. tokenized_tweet.head()

推文中单词的可视化理解

到目前为止,我们已经完成对数据的预处理,之后就是探索这些数据,从中获得重要理解。在开始探索前,结合任务目标,我们可能会产生一些新的问题:

  • 整个数据集中出现频率最高的单词是哪个?

  • 仇恨言论和非仇恨言论推文中,出现频率最高的单词又分别是哪个?

  • 一条推文中有几个词例?

  • 哪种趋势和数据集本身有关?

  • 哪种趋势和这两种言论有关?它们和相应情感相符吗?

1. 找出推文中的常用词:WordCloud

为了查看单体在整个训练集中的分布情况,一种可行的方法是绘制WordCloud图,这是一种可视化形式,能把出现频率较高的词放大,把出现频率最高的较低的词缩小。

  
  
    
  1. all_words = ' '.join([text for text in combi['tidy_tweet']])

  2. from wordcloud import WordCloud

  3. wordcloud = WordCloud(width=800, height=500, random_state=21, max_font_size=110).generate(all_words)

  4. plt.figure(figsize=(10, 7))

  5. plt.imshow(wordcloud, interpolation="bilinear")

  6. plt.axis('off')

  7. plt.show()

如上图所示,大多数单词是积极的或中立的,其中“happy”“love”最为常见,从它们身上我们找不到和仇恨言论有关的内容。所以接下来,我们会为标签为“1”和“0”的两类数据单独绘制WordCloud,并以此查看词频分布情况。

2. 非种族主义/性别歧视推文中的单词

  
  
    
  1. normal_words =' '.join([text for text in combi['tidy_tweet'][combi['label'] == 0]])

  2. wordcloud = WordCloud(width=800, height=500, random_state=21, max_font_size=110).generate(normal_words)

  3. plt.figure(figsize=(10, 7))

  4. plt.imshow(wordcloud, interpolation="bilinear")

  5. plt.axis('off')

  6. plt.show()

和之前一样,大多数词是积极的或中立的,其中“happy”“smile”“love”最常见。

3. 种族主义/性别歧视推文的单词

  
  
    
  1. negative_words = ' '.join([text for text in combi['tidy_tweet'][combi['label'] == 1]])

  2. wordcloud = WordCloud(width=800, height=500,

  3. random_state=21, max_font_size=110).generate(negative_words)

  4. plt.figure(figsize=(10, 7))

  5. plt.imshow(wordcloud, interpolation="bilinear")

  6. plt.axis('off')

  7. plt.show()

我们可以清楚地看到,大多数词语都有负面含义。这正好是一个非常出色的文本数据,之后我们可以基于它在twitter数据中添加主题标签/趋势。

4. 主题标签对推文情感的影响

twitter里的主题标签#就相当于国内社交平台的话题,表示推文包含某个特定时间点的热搜内容。这是文本中一项重要内容,我们可以利用这些标签探索它们和推文情感的关系。

例如,下面是我们数据集中的一条推文:

这段内容涉及性别歧视,而它的主题标签也传达了同样的意思。我们把这些标签放进两类推特文本的表格中,看看这些内容的出现情况。

  
  
    
  1. # function to collect hashtags

  2. def hashtag_extract(x):

  3.    hashtags = []

  4.    # Loop over the words in the tweet

  5.    for i in x:

  6.        ht = re.findall(r"#(\w+)", i)

  7.        hashtags.append(ht)

  8.    return hashtags

  
  
    
  1. # extracting hashtags from non racist/sexist tweets

  2. HT_regular = hashtag_extract(combi['tidy_tweet'][combi['label'] == 0])

  3. # extracting hashtags from racist/sexist tweets

  4. HT_negative = hashtag_extract(combi['tidy_tweet'][combi['label'] == 1])

  5. # unnesting list

  6. HT_regular = sum(HT_regular,[])

  7. HT_negative = sum(HT_negative,[])

  • 非种族主义/性别歧视推文

  
  
    
  1. a = nltk.FreqDist(HT_regular)

  2. d = pd.DataFrame({'Hashtag': list(a.keys()),

  3.                  'Count': list(a.values())})

  4. # selecting top 10 most frequent hashtags    

  5. d = d.nlargest(columns="Count", n = 10)

  6. plt.figure(figsize=(16,5))

  7. ax = sns.barplot(data=d, x= "Hashtag", y = "Count")

  8. ax.set(ylabel = 'Count')

  9. plt.show()

非种族主义/性别歧视推文出现频率较高的主题标签都是积极的、正面的,这不难理解。那么我们来看看种族主义/性别歧视推文中的情况。

  • 种族主义/性别歧视推文

  
  
    
  1. b = nltk.FreqDist(HT_negative)

  2. e = pd.DataFrame({'Hashtag': list(b.keys()), 'Count': list(b.values())})

  3. # selecting top 10 most frequent hashtags

  4. e = e.nlargest(columns="Count", n = 10)  

  5. plt.figure(figsize=(16,5))

  6. ax = sns.barplot(data=e, x= "Hashtag", y = "Count")

  7. ax.set(ylabel = 'Count')

  8. plt.show()

正如预期的那样,大多数标签都是负面的,也有一些中性标签。所以我们把这些主题标签保留下来是个明确的选择,它们确实包含区分仇恨言论和非仇恨言论的关键信息。

从推文中提取特征

如果要分析预处理数据,首先我们要把它们转换为特征。现在,构建文本特征的方法有很多,比如词袋模型、TF-IDF和词嵌入。在这个问题下,我们主要介绍前两种方法。

1. 词袋特征

词袋(Bag of Words,简称BoW)是一种统计某个词在一份文档中出现次数的算法,统计所得的词频数据可以用于比较文档并测量其相似性。假设我们手头有一个语料库C {d1,d2…..dD}(D个文本),它包含N个唯一词例(单词),那么它的词袋矩阵大小M就等于N×D。矩阵M中的每一行包含文档D(i)中的词例出现频率。

让我们用一个直观的例子来理解这一点。假设我们有两个文本:

  • D1:He is a lazy boy. She is also lazy.

  • D2:Smith is a lazy person.

它们包含的唯一词例是[‘He’,’She’,’lazy’,’boy’,’Smith’,’person’],所以D=2,N=6,矩阵M=2×6,也就是:

上述矩阵中的列可用作构建分类模型的特征,当然,提到词袋,首选sklearn,它的CountVectorizer函数可以直接创建词袋特征。我们设max_features = 1000,取词频排名前1000的词例。

  
  
    
  1. from sklearn.feature_extraction.text import CountVectorizer

  2. bow_vectorizer = CountVectorizer(max_df=0.90, min_df=2, max_features=1000, stop_words='english')

  3. # bag-of-words feature matrix

  4. bow = bow_vectorizer.fit_transform(combi['tidy_tweet'])

2. TF-IDF特征

这是另一种基于词频的方法,它和词袋方法的不同之处在于它不仅考虑单个文档(或推文)中单词的出现次数,而且考虑整个语料库。

虽然是基于词频,但TF-IDF测量的是相关性,而非频率。首先,它会统计某一特定文档中的词的出现次数,但是,由于“and”、“the”之类的词所有文档中都频繁出现,这些词的频率需要调整。这就是逆文档频率的部分。出现某一个词的文档数量越多,这个词作为信号的价值就越小。这样做的目的是仅留下独特的高频词用作标记。每个词的TF-IDF相关性是一种归一化的数据格式,总和也是1。

  • TF:词例t出现在文档中的次数/文档词例总数

  • IDF = log(N/n),其中N是文档总数,n是文档中词例t出现的次数

  • TF-IDF = TF×IDF

  
  
    
  1. from sklearn.feature_extraction.text import TfidfVectorizer

  2. tfidf_vectorizer = TfidfVectorizer(max_df=0.90, min_df=2, max_features=1000, stop_words='english')

  3. # TF-IDF feature matrix

  4. tfidf = tfidf_vectorizer.fit_transform(combi['tidy_tweet'])


模型构建:情感分析

现在,数据已经处理好了,数据的数字特征也已经被提取出来,最后就是用逻辑回归构建模型。

1. 用词袋特征构建模型

  
  
    
  1. from sklearn.linear_model import LogisticRegression

  2. from sklearn.model_selection import train_test_split

  3. from sklearn.metrics import f1_score

  4. train_bow = bow[:31962,:]

  5. test_bow = bow[31962:,:]

  6. # splitting data into training and validation set

  7. xtrain_bow, xvalid_bow, ytrain, yvalid = train_test_split(train_bow, train['label'], random_state=42, test_size=0.3)

  8. lreg = LogisticRegression()

  9. lreg.fit(xtrain_bow, ytrain) # training the model

  10. prediction = lreg.predict_proba(xvalid_bow) # predicting on the validation set

  11. prediction_int = prediction[:,1] >= 0.3 # if prediction is greater than or equal to 0.3 than 1 else 0

  12. prediction_int = prediction_int.astype(np.int)

  13. f1_score(yvalid, prediction_int) # calculating f1 score

输出:0.525。

这个模型的F1 score是0.525,我们把它放到测试集上进行预测:

  
  
    
  1. test_pred = lreg.predict_proba(test_bow)

  2. test_pred_int = test_pred[:,1] >= 0.3

  3. test_pred_int = test_pred_int.astype(np.int)

  4. test['label'] = test_pred_int

  5. submission = test[['id','label']]

  6. submission.to_csv('sub_lreg_bow.csv', index=False) # writing data to a CSV file

得分:0.537。

2. TF-IDF特征

  
  
    
  1. train_tfidf = tfidf[:31962,:]

  2. test_tfidf = tfidf[31962:,:]

  3. xtrain_tfidf = train_tfidf[ytrain.index]

  4. xvalid_tfidf = train_tfidf[yvalid.index]

  5. lreg.fit(xtrain_tfidf, ytrain)

  6. prediction = lreg.predict_proba(xvalid_tfidf)

  7. prediction_int = prediction[:,1] >= 0.3

  8. prediction_int = prediction_int.astype(np.int)

  9. f1_score(yvalid, prediction_int)

输出:0.538,最终得分:0.547,比起词袋特征有所改善。

以上就是twitter情感分析模型构建的全部教程,希望本文对你有帮助。

原文地址:www.analyticsvidhya.com/blog/2018/07/hands-on-sentiment-analysis-dataset-python/

登录查看更多
30

相关内容

狭义的情感分析(sentiment analysis)是指利用计算机实现对文本数据的观点、情感、态度、情绪等的分析挖掘。广义的情感分析则包括对图像视频、语音、文本等多模态信息的情感计算。简单地讲,情感分析研究的目标是建立一个有效的分析方法、模型和系统,对输入信息中某个对象分析其持有的情感信息,例如观点倾向、态度、主观观点或喜怒哀乐等情绪表达。

知识荟萃

精品入门和进阶教程、论文和代码整理等

更多

查看相关VIP内容、论文、资讯等
【实用书】Python机器学习Scikit-Learn应用指南,247页pdf
专知会员服务
255+阅读 · 2020年6月10日
最新《自动微分手册》77页pdf
专知会员服务
97+阅读 · 2020年6月6日
干净的数据:数据清洗入门与实践,204页pdf
专知会员服务
160+阅读 · 2020年5月14日
【干货书】R语言书: 编程和统计的第一课程,
专知会员服务
106+阅读 · 2020年5月9日
【干货书】机器学习Python实战教程,366页pdf
专知会员服务
330+阅读 · 2020年3月17日
【经典书】Python数据数据分析第二版,541页pdf
专知会员服务
189+阅读 · 2020年3月12日
【LinkedIn报告】深度自然语言处理的搜索系统,211页pdf
专知会员服务
105+阅读 · 2019年6月21日
如何使用自然语言工具包(NLTK)在Python3中执行情感分析
Python程序员
18+阅读 · 2019年10月28日
ML通用指南:文本分类详细教程(上)
论智
19+阅读 · 2018年7月29日
深度学习线性代数简明教程
论智
11+阅读 · 2018年5月30日
教你用Python进行自然语言处理(附代码)
数据派THU
6+阅读 · 2018年3月28日
Tensorflow 文本分类-Python深度学习
Python程序员
12+阅读 · 2017年11月22日
在深度学习TensorFlow 框架上使用 LSTM 进行情感分析
北京思腾合力科技有限公司
4+阅读 · 2017年8月9日
Arxiv
7+阅读 · 2018年1月24日
Arxiv
25+阅读 · 2018年1月24日
Arxiv
12+阅读 · 2018年1月20日
Arxiv
3+阅读 · 2017年12月18日
Arxiv
5+阅读 · 2015年9月14日
VIP会员
相关VIP内容
【实用书】Python机器学习Scikit-Learn应用指南,247页pdf
专知会员服务
255+阅读 · 2020年6月10日
最新《自动微分手册》77页pdf
专知会员服务
97+阅读 · 2020年6月6日
干净的数据:数据清洗入门与实践,204页pdf
专知会员服务
160+阅读 · 2020年5月14日
【干货书】R语言书: 编程和统计的第一课程,
专知会员服务
106+阅读 · 2020年5月9日
【干货书】机器学习Python实战教程,366页pdf
专知会员服务
330+阅读 · 2020年3月17日
【经典书】Python数据数据分析第二版,541页pdf
专知会员服务
189+阅读 · 2020年3月12日
【LinkedIn报告】深度自然语言处理的搜索系统,211页pdf
专知会员服务
105+阅读 · 2019年6月21日
相关资讯
如何使用自然语言工具包(NLTK)在Python3中执行情感分析
Python程序员
18+阅读 · 2019年10月28日
ML通用指南:文本分类详细教程(上)
论智
19+阅读 · 2018年7月29日
深度学习线性代数简明教程
论智
11+阅读 · 2018年5月30日
教你用Python进行自然语言处理(附代码)
数据派THU
6+阅读 · 2018年3月28日
Tensorflow 文本分类-Python深度学习
Python程序员
12+阅读 · 2017年11月22日
在深度学习TensorFlow 框架上使用 LSTM 进行情感分析
北京思腾合力科技有限公司
4+阅读 · 2017年8月9日
相关论文
Arxiv
7+阅读 · 2018年1月24日
Arxiv
25+阅读 · 2018年1月24日
Arxiv
12+阅读 · 2018年1月20日
Arxiv
3+阅读 · 2017年12月18日
Arxiv
5+阅读 · 2015年9月14日
Top
微信扫码咨询专知VIP会员