TowardsDataScience 博客中文翻译 2019(四百四十)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

情感分析很难,但 AI 可能有答案。

原文:https://towardsdatascience.com/sentiment-analysis-is-difficult-but-ai-may-have-an-answer-a8c447110357?source=collection_archive---------15-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image by Magic Creative from Pixabay

最近,当我在亚马逊上购买一个笔记本电脑包时,我偶然发现了一条非常有趣的顾客评论:

“这是有史以来最好的电脑包。它太好了,用了不到两个月,就配当杂货袋用了。”

评论中固有的讽刺是显而易见的,因为用户对包的质量不满意。然而,由于该句包含“最好”、“好”和“值得”等词,该评论很容易被误认为是积极的。这种幽默但隐晦的评论在社交媒体上传播是一种常见现象。如果这种反应没有被发现并采取行动,可能会损害公司的声誉,特别是如果他们计划举行新的发布会。检测评论中的讽刺是自然语言处理的一个重要用例,我们将看到机器学习如何在这方面有所帮助。

情感分析:从非结构化数据中获得重要见解

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Source: 5 ways sentiment analysis can boost your business

在我们进入讽刺检测的本质之前,让我们试着对情感分析有一个整体的概述。

情感分析,也被称为观点挖掘,是自然语言处理的一个子领域,试图从给定的文本中识别和提取观点。

早些时候,公司依靠调查和焦点小组研究等传统方法来获得消费者的反馈。然而,机器学习和人工智能支持的技术使得分析来自各种来源的文本更加准确和精确成为可能。不用说,从文本中提取情感的能力是一个非常有价值的工具,有可能极大地提高许多企业的投资回报率。

情感分析的重要性

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Advantages of Sentiment Analysis in driving Business

时空洞察的首席技术官保罗·霍夫曼曾经说过*“如果你想理解人们,尤其是你的客户……那么你必须具备强大的文本分析能力*”。我们完全同意 Paul 的观点,因为文本分析给企业带来的力量在最近几年已经非常明显。随着社交媒体活动的激增,从商业角度来看,情感被视为有价值的商品。通过仔细衡量人们的意见和情绪,公司可以合理地了解人们对产品的看法,并相应地纳入反馈。

讽刺:用积极的词语表达消极的情绪

情感分析不是一项容易完成的任务。文本数据通常预先加载了大量噪声。讽刺是一种天生存在于社交媒体和产品评论中的噪音,可能会干扰结果。

讽刺性的文章展示了一种独特的行为。与简单的否定不同,讽刺性的句子只使用词语的正面含义来表达负面情绪。这里有几个明显带有讽刺意味的例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

source: Semi-Supervised Recognition of Sarcastic Sentences in Online Product Reviews

情感分析很容易被这种讽刺性词语的存在误导,因此,讽刺检测是许多 NLP 任务中至关重要的预处理步骤。在为 NLP 应用训练模型之前,识别并去除噪声样本是有用的。

使用无人驾驶人工智能(DAI)的讽刺检测

无人驾驶 AI 是来自 H2O.ai 的自动机器学习产品。它配备了用于文本分类和回归问题的自然语言处理(NLP)方法。该平台支持独立文本和具有其他数值的文本作为预测特征。以下配方和模型已在 DAI 中实施:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Key Capabilities of the Driverless AI NLP Recipe

该平台使用 TFIDF、CNN 和 GRU 等强大的技术自动将文本字符串转换为特征。通过 TensorFlow,无人驾驶 AI 还可以处理更大的文本块,并使用所有可用的数据建立模型来解决商业问题。无人驾驶人工智能具有最先进的情感分析 NLP 能力,我们将利用它来建立一个讽刺检测分类器。

资料组

该数据集由互联网评论网站 Reddit 的 130 万条讽刺评论组成,分为讽刺和非讽刺两类。数据集的来源是一篇论文,题目是:“ 一个大型的自我注释讽刺语料库 ”。数据集的处理版本也可以在 Kaggle 上找到,让我们在运行各种分类算法之前探索一下数据集。

导入数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据集包含一百万行,每条记录包含十个属性:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们主要对以下两列感兴趣:

  • label : 0用于讽刺性评论,1用于非讽刺性评论
  • comment:将用于运行实验的文本栏

探索性数据分析

数据集非常平衡,讽刺和非讽刺的推特数量相等。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

讽刺和正常评论的长度分布也几乎相同。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Distribution of Sarcastic vs Non-Sarcastic Comments

由于数据集已被转换为表格格式,它已准备好输入无人驾驶人工智能。请注意,文本特征将在特征工程过程中自动生成和评估

启动实验

我们将分三部分进行实验,以获得尽可能好的结果。

  • 内置 TF/IDF NLP 配方

在第一部分中,我们将使用 DAI 的内置 TF/IDF 功能。

如果你想更新一下关于无人驾驶人工智能入门的知识,请随时参加 试驾 。试驾是 H2O 在 AWS 云上的无人驾驶人工智能,你可以探索它的所有功能,而不必下载它。

重新开始戴的生活。接下来,以 70:30 的比例将数据集分成训练集和测试集,并将label指定为目标列。我们还将取消选择所有其他列,只保留数据集中的comment列。最后,选择LogLoss作为评分者,其他参数保持默认,开始实验。屏幕应该如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sentiment Analysis with built-in NLP recipes

  • 内置 Tensorflow NLP 配方

作为替代,我们将启动相同实验的另一个实例,但是使用 Tensorflow 模型。这是因为 TextCNN 依赖于张量流模型。点击“Expert Settings’选项卡,打开‘TensorFlow Models’。其余的过程保持不变。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sentiment Analysis with built-in Tensorflow recipes

  • 带自定义人气食谱

如果内置的配方还不够,那么就有必要构建我们自己的配方,专注于我们的特定用例。DAI 的最新版本(1.7.0)实现了一个名为 BYOR 的关键功能,代表 【自带菜谱】。该功能旨在使数据科学家能够根据其业务需求定制 DAI。你可以在这里阅读更多关于这个功能的信息。

要上传定制配方,请进入专家设置并上传所需配方。H2O 已经构建并开源了超过 80 个食谱可以作为模板。这些食谱可以从 https://github.com/h2oai/driverlessai-recipes获得。对于这个实验,我们将使用下面的配方:

  • 使用来自 TextBlob 的预训练模型从文本中提取情感。

TextBlob 是一个 python 库,提供了一个简单的 API 来访问它的方法和执行基本的 NLP 任务。它可以执行许多 NLP 任务,如情感分析、拼写检查、摘要创建、翻译等。点击专家设置选项卡并导航至driverlessai-recipes > transformers > nlp并选择所需的制作方法。点击save保存设置。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来,您还可以选择特定的变压器并取消选择其余的变压器。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

实验结果总结

下面的截图显示了不同配方的戴的三个实例之间的比较。自定义配方的引入将 Logloss 组件从 0.54 减少到 0.50,当转换到业务领域时,可以具有巨大的价值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一旦实验完成,用户可以进行新的预测,并下载评分管道,就像其他任何无人驾驶 AI 实验一样。

结论

情感分析在营销领域可以发挥至关重要的作用。它可以帮助创建有针对性的品牌信息,并帮助公司了解消费者的偏好。对于一家公司来说,这些见解对于扩大其在一系列行业的影响力至关重要。

Python 中 Anthem 游戏发布的情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-anthem-game-launch-in-python-16be9e5083d2?source=collection_archive---------14-----------------------

视频游戏的发布受到戏剧的困扰。从误导性的预购捆绑包,到发布时远未完成的游戏,大型发行商在决定游戏发布的方式和时间时有相当大的风险要管理。我认为这可能是一个有趣的项目,看看一个游戏在推出期间的情绪变化,AAA 冠军国歌是这个小项目的完美游戏。(仅供参考,我在 2 月 22 日游戏正式发布前写这篇文章)

在我们开始之前,Anthem 有一个独特的发布时间表,可能会影响个人对游戏的看法。

  • Anthem 从 2 月 1 日星期五到 2 月 3 日星期日有一个“演示周末”
  • Anthem 于 2 月 15 日星期五“提前”面向 EA Access 成员推出
  • Anthem 将于 2 月 22 日正式面向所有人发布

所以让我们开始吧!

我将尽力描述我使用的所有软件包,但这里有我的重要陈述供参考!

%matplotlib inline
from twitterscraper import query_tweets
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
import datetime as dt
import pandas as pd
from langdetect import detect
import matplotlib.pyplot as plt
import seaborn as snsanalyzer = SentimentIntensityAnalyzer()

抓取 Twitter 数据

从 twitter 获取数据的方法有一百万种,但我选择使用 taspinar 的软件包twitterscraper,它是 beautifulSoup 的一个包装器,使获取 tweets 变得容易。我喜欢这个包,不仅因为你不必向 twitter 请求 API 密钥,还因为 webscraper 没有 Twitter API 的任何限制。

有了from twitterscraper import query_tweets,获取我需要的所有推文变得简单了。

begin_date = dt.datetime.strptime("Jan 15 2019", "%b %d %Y").date()
tweets = query_tweets("#Anthem OR #AnthemGame",begindate=begin_date)

这需要一些时间…所以在你等待的时候去攻克一个要塞吧!完成后,你应该有一个很长的 twitterscraper 对象列表。

print(len(tweets))
102418

102418 条关于 Anthem 的推文!

Twitterscraper 对象有一个易于使用的 dict 方法,它以字典的形式返回我们想要的所有 tweet 数据。

tweets[1].__dict__{'user': '_WECKLESS',
 'fullname': 'WECKLESS™',
 'id': '1085323189738192897',
 'url': '/_WECKLESS/status/1085323189738192897',
 'timestamp': datetime.datetime(2019, 1, 15, 23, 49, 47),
 'text': 'Here is my GIF #AnthemGame pic.twitter.com/jCNjiWQnmJ',
 'replies': 0,
 'retweets': 0,
 'likes': 2,
 'html': '<p class="TweetTextSize js-tweet-text tweet-text" data-aria-label-part="0" lang="en">Here is my GIF <span class="twitter-hashflag-container"><a class="twitter-hashtag pretty-link js-nav" data-query-source="hashtag_click" dir="ltr" href="/hashtag/AnthemGame?src=hash"><s>#</s><b><strong>AnthemGame</strong></b></a><a dir="ltr" href="/hashtag/AnthemGame?src=hash"><img alt="" class="twitter-hashflag" draggable="false" src="https://abs.twimg.com/hashflags/AnthemGame_Anthem/AnthemGame_Anthem.png"/></a></span> <a class="twitter-timeline-link u-hidden" data-pre-embedded="true" dir="ltr" href="https://t.co/jCNjiWQnmJ">pic.twitter.com/jCNjiWQnmJ</a></p>'}

我们可以看到这本字典有用户名,唯一的推文 id,回复数,转发数,推文的点赞数,最重要的是推文的文本!我们将把所有这些推文放入一个熊猫数据框架中,这样它们就容易使用了!此时,我还将我的推文保存到一个文件中,这样,如果我想重新运行我的分析,我就不必再次经历网络搜集过程。)

tweet_list = (t.__dict__ for t in tweets)
df = pd.DataFrame(tweet_list)

这是我们新的数据框架的样子!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Notice how some tweets are not in english. We’ll deal with that in the next step!

语言和情感分析

下一步我们要解决两件事。首先,请注意,我们的推文并非都是英文的。虽然我们可以翻译我们的推文,并试图从它们那里获得一些情感,但我认为删除非英语推文会更容易、更干净。要做到这一点,我们需要给每条推文贴上语言标签。别担心,那里有一个图书馆! Langdetect by Mimino66 的 detect 功能就是我们识别推文语言所需要的一切。我们可以用from langdetect import detect载入必要的功能

我们将通过在文本数据上映射 detect()函数,在数据帧中创建一个新列,然后只保留英语的 tweets。

df['lang'] = df['text'].map(lambda x: detect(x))
df = df[df['lang']=='en']

当这一步完成时,我只剩下 77,740 条推文。

现在,我们可以开始对我们的推文进行一些文本分析了。 VADER 情感分析是一个流行的 python 包,用于获取一段文本的情感,它特别适合社交媒体数据,并且随时可以开箱即用!

我们需要导入它的 SentimentIntensityAnalyzer 并初始化它。

from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
analyzer = SentimentIntensityAnalyzer()

VADER 会为你传递的任何文本返回一个 4 分的字典;正分数、中性分数、负分数和复合分数,范围从-1 到 1。我们最感兴趣的是追踪推文整体情绪的复合分数。

从这里,我们制作了一系列新的数据,包含我们的推文文本的情感,并将其连接到我们的原始数据帧。

sentiment = df['text'].apply(lambda x: analyzer.polarity_scores(x))
df = pd.concat([df,sentiment.apply(pd.Series)],1)

这是我们最终的数据帧。我们可以看到我们的推文是英文的,每条推文都有一组相关的情感评分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在开始分析!

分析情绪

首先,让我们调用df.describe()并获取数据集的一些基本信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们有 77,740 条推文,平均有 10 个赞,35 个回复和 2 个转发。查看复合得分,我们可以看到平均推文是积极的,平均情绪为 0.21。

绘制这些数据会让我们更好地了解它的样子。在我们绘图之前,为了方便使用,我对我的数据框架做了一些更改,按时间戳对所有值进行排序,使它们有序,将时间戳复制到索引以使绘图更容易,并计算复合情感得分的扩展和滚动平均值。

df.sort_values(by='timestamp', inplace=True)
df.index = pd.to_datetime(df['timestamp'])df['mean'] = df['compound'].expanding().mean()
df['rolling'] = df['compound'].rolling('6h').mean()

现在使用 matplotlib 和import matplotlib.pyplot as plt,我们可以创建一个快速图表,显示我们的推文和他们的情绪随时间的变化。

fig = plt.figure(figsize=(20,5))
ax = fig.add_subplot(111)
ax.scatter(df['timestamp'],df['compound'], label='Tweet Sentiment')
ax.plot(df['timestamp'],df['rolling'], color ='r', label='Rolling Mean')
ax.plot(df['timestamp'],df['mean'], color='y', label='Expanding Mean')
ax.set_xlim([dt.date(2019,1,15),dt.date(2019,2,21)])
ax.set(title='Anthem Tweets over Time', xlabel='Date', ylabel='Sentiment')
ax.legend(loc='best')
fig.tight_layout()
plt.show(

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以马上注意到一些有趣的事情。

  • 有很多推特的情绪分是 0。
  • 我们有很多数据。
  • 在我们的数据中,平均值似乎有些稳定,除了第 25 天,那里的负面推文数量有所增加,平均值的扩大受到了严重影响。
  • 似乎有更高密度的区域有更多的推文出现。我们将看看我们是否能把这些与游戏发布的相关事件联系起来。

让我们试着一次解决一个问题。首先让我们看看那些情绪为 0 的推文。Seborn 的 distplot 是一种快速查看我们推文中情感分数分布的方法。

fig = plt.figure(figsize=(10,5))
ax = fig.add_subplot(111)
sns.distplot(df['compound'], bins=15, ax=ax)
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Just over 30% of our tweets have a sentiment of 0.

我选择暂时将这些推文留在我的数据集中。但值得注意的是,如果不包括这些因素,平均情绪会高得多。

让我们看看,随着时间的推移,我们是否能对自己的情绪有一个更清晰的了解。总的来说,我们的数据是嘈杂的,实在是太多了。从我们的数据中提取一个样本可能会让我们更容易看到趋势的发展。我们将使用 pandas sample()函数来保留 77,740 条推文中的十分之一。

ot = df.sample(frac=.1, random_state=1111)
ot.sort_index(inplace=True)ot['mean'] = ot['compound'].expanding().mean()
ot['rolling'] = ot['compound'].rolling('6h').mean()

我按日期重新排序,并为我们的数据计算新的扩展和滚动平均值,并绘制新数据集的图表。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

By sampling the dataset we can get a much better idea of how sentiment is changing over time.

这个图表好得多,让我们可以看到随着时间的推移,情绪的一些下降和趋势。现在剩下要做的就是找出是什么导致了情绪的变化。

我在本文开头提到了 Anthem 发布的一些重要注意事项。让我们在图表中添加一些重要的日期,看看它们是否符合我们数据中的趋势。

  • Anthem 从 2 月 1 日到 2 月 3 日有一个“免费演示周末”。
  • Anthem 于 2 月 15 日面向 Origin Access 会员上线。
  • Anthem 在 2 月 15 日发布后不久就出现了服务器问题,并于上午 7:30 发布到他们的 twitter 帐户上,这些问题得到了解决,EA 于上午 11:06 发布了一篇 twitter 帖子。
  • EA 于 19 日发布了第一天补丁,20 日上午 8:13 发布了完整的补丁说明,补丁于当天下午 4:27 上线。

添加一些行。axvline()和。text()我在这里结束了这个图表。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

These lines might not line up perfectly, as I’m not sure the ‘official’ time of each release.

我们可以看到,两大群推文与游戏发布时间一致,都是“演示周末”和 Origin Access 发布。

此外,我们可以看到,在演示周末,情绪下降。演示周末期间的平均情绪为 0.138,相比之下,演示周末之前的同一时期的平均情绪为 0.239。

你也可以很快注意到,1 月下旬还有另一组推文未被解释。快速浏览 Twitter,我发现这实际上是一个 VIP 演示周末,也遇到了服务器问题,加载时间长,需要多个补丁修复。这与市场人气的大幅下降不谋而合。我们也将这条线添加到我们的图表中,并创建一些支线剧情,让我们可以看到一些个别事件的细节。

这里是图形的最终代码,后面是图形本身。

fig = plt.figure(figsize=(20,5))
ax=fig.add_subplot(111)ax.scatter(ot['timestamp'],ot['compound'], label='Tweet Sentiment')
ax.plot(ot['timestamp'],ot['rolling'], color ='r', label='Rolling Mean')
ax.plot(ot['timestamp'],ot['mean'], color='y', label='Expanding Mean')
ax.set_xlim([dt.date(2019,1,15),dt.date(2019,2,21)])
ax.set(title='Anthem Tweets over Time', xlabel='Date', ylabel='Sentiment')
ax.legend(loc='best')#free demo weekend
ax.axvline(x=dt.datetime(2019,2,1) ,linewidth=3, color='r')
ax.text(x=dt.datetime(2019,2,1), y=0, s='Demo Weekend Starts', rotation=-90, size=10)ax.axvline(x=dt.datetime(2019,2,4) ,linewidth=3, color='r')
ax.text(x=dt.datetime(2019,2,4), y=0, s='Demo Weekend Ends', rotation=-90, size=10)#origin access launch
ax.axvline(x=dt.datetime(2019,2,15) ,linewidth=3, color='r', linestyle='dashed')
ax.text(x=dt.datetime(2019,2,15), y=0, s='Origin Access Launch', rotation=-90, size=10)#server fix
ax.axvline(x=dt.datetime(2019,2,15,11,6) ,linewidth=3, color='r')
ax.text(x=dt.datetime(2019,2,15,11,6), y=0, s='Server Up', rotation=-90, size=10)#patchnotes announced
ax.axvline(x=dt.datetime(2019,2,19,12) ,linewidth=3, color='r')
ax.text(x=dt.datetime(2019,2,19,12), y=0, s='Patch Notes Announced', rotation=-90, size=10)#patchnotes released
ax.axvline(x=dt.datetime(2019,2,20,8,13) ,linewidth=3, color='r')
ax.text(x=dt.datetime(2019,2,20,8,13), y=0, s='Patch Notes Released', rotation=-90, size=10)#patch realeased
ax.axvline(x=dt.datetime(2019,2,20,16,27) ,linewidth=3, color='r')
ax.text(x=dt.datetime(2019,2,20,16,27), y=0, s='Patch Released', rotation=-90, size=10)#vip weekend
ax.axvline(x=dt.datetime(2019,1,25,9,0) ,linewidth=3, color='r')
ax.text(x=dt.datetime(2019,1,25,9,0), y=0, s='VIP Demo', rotation=-90, size=10)fig.tight_layout()
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Again, the lines might not be perfect as I’m unsure of the ‘official’ time of each launch.

这是添加了 VIP 演示的大图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们最终的图表向我们展示了一些有趣的事情。首先,VIP 演示对情绪影响最大。很明显,个人对围绕 VIP 演示的所有问题感到不安。

公开演示周末也显示了情绪的显著下降。这两个都是有趣的案例,在这两个案例中,开发者在游戏没有完全测试之前就决定允许公众玩游戏。一方面,开发者和发行商得到了关于游戏、服务器容量和需要修复的错误的有价值的反馈。问题是,这是以游戏周围的情绪为代价的吗?

也许不是!我们可以看到,当 EA Access 发布开始时,人气已经恢复到原来的水平(尽管从未像 VIP 试玩前那样高。)

游戏开发商和发行商需要权衡让公众作为早期游戏发布的 beta 测试者的价值,以及公众对游戏的看法。如果演示周末被宣传为“测试”周末,或许个人情绪会更高…

总而言之,这是一个有趣的项目,同样的分析可以应用于各种事物,政治,电影等等。现在我想我要从统计中休息一会儿,去参加我的标枪飞行。

《神盾局》主角的情感分析

原文:https://towardsdatascience.com/sentiment-analysis-of-the-lead-characters-on-f-r-i-e-n-d-s-51aa5abf1fa6?source=collection_archive---------29-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Central Perk — Where this beautiful journey began.

我是这部美国情景喜剧的最大爱好者之一——自从我开始看这部剧以来就是朋友。最近,我开始在网上寻找这个节目的文字记录(https://fangj.github.io/friends/)。我在这些抄本上找不到太多的数据科学,除了每个角色对话数量的简单统计,他们说出的名字的数量和类似的统计。我想如果我能为像我一样的观众做更多的事情,从数据科学的角度更广泛地了解这部剧,那将会很有趣。

作为第一步,我整理了 plain 可以获得的所有 html 脚本(全部 10 季)。csv 文件(也可以复制成文本,不会造成差异)。皈依者。所有赛季的 csv 文件都可以从我的 github 链接获取——(https://github . com/shilpibattacharyya/Friends _ Analysis/tree/master/transcripts _ Friends)。然后,我使用下面的命令将它们合并在一起。

## Command to append multiple files in a directory - 1* represent all files for season1 and so on ...#sed 1d 1*.csv 2*.csv 3*.csv 4*.csv 5*.csv 6*.csv 7*.csv 8*.csv 9*.csv 100*.csv> merged.csv *

然后使用下面的实用程序将每个角色(瑞秋、罗斯、乔伊、菲比、钱德勒、莫妮卡)的对白分开:

def rem_tabs_newline(str_val):
    str_val = str_val.strip('\\n')
    str_val = str_val.strip('\\t')
    str_val = str_val.replace('\\n','')
    str_val = str_val.replace('\\t','')
    return str_valfriends_chars={} 
Rachel=''
Ross=''
Joey=''
Chandler=''
Phoebe=''
Monica=''
with open("transcripts_friends/season_all/merged.csv", "r+") as fp:
    for cnt, line in enumerate(fp):
        if line.startswith('Rachel:'):
            Rachel=Rachel+' '+(line[8:])
        elif line.startswith('Ross:'):
            Ross=Ross+' '+(line[6:])
        elif line.startswith('Monica:'):
            Monica=Monica+' '+(line[8:])
        elif line.startswith('Chandler:'):
            Chandler=Chandler+' '+(line[10:])
        if line.startswith('Phoebe:'):
            Phoebe=Phoebe+' '+(line[8:])
        if line.startswith('Joey:'):
            Joey=Joey+' '+(line[6:])friends_chars['RACHEL']=rem_tabs_newline(Rachel)
friends_chars['ROSS']=rem_tabs_newline(Ross)
friends_chars['MONICA']=rem_tabs_newline(Monica)
friends_chars['PHOEBE']=rem_tabs_newline(Phoebe)
friends_chars['CHANDLER']=rem_tabs_newline(Chandler)
friends_chars['JOEY']=rem_tabs_newline(Joey)

下面的代码使用 nltk 库清除数据,删除停用词、制表符和换行符。

from nltk.corpus import stopwords 
from nltk.tokenize import word_tokenize 
from nltk.tokenize import sent_tokenizestop_words = set(stopwords.words('english'))def clean_data(val):
    val = val.strip('\\n')
    val = val.strip('\\t')
    val = val.replace('\\n','')
    val = val.replace('\\t','')
    word_tokens = word_tokenize(str(val).lower().strip('[]') )
    filtered_sentence = [w for w in word_tokens if not w in stop_words]filtered_sentence = []for w in word_tokens: 
        if w not in stop_words: 
            filtered_sentence.append(w)
    return list(filtered_sentence)

一旦我清理了数据并收集了单词,我就为每个字符创建一个集合语料库列表,如下所示。

rachel_corpus=list(set(clean_data(str(friends_chars['RACHEL']).strip('[]'))))
ross_corpus=list(set(clean_data(str(friends_chars['ROSS']).strip('[]'))))
mon_corpus=list(set(clean_data(str(friends_chars['MONICA']).strip('[]'))))
joe_corpus=list(set(clean_data(str(friends_chars['JOEY']).strip('[]'))))
phoebs_corpus=list(set(clean_data(str(friends_chars['PHOEBE']).strip('[]'))))
chandler_corpus=list(set(clean_data(str(friends_chars['CHANDLER']).strip('[]'))))

然后,只过滤掉长度大于 3 的单词,这样我就可以去掉常见的单词,如下所示。

words_rach=[w for w in rachel_corpus if len(w)>3]
words_mon=[w for w in mon_corpus if len(w)>3]
words_ross=[w for w in ross_corpus if len(w)>3] 
words_phoebs=[w for w in phoebs_corpus if len(w)>3]
words_joe=[w for w in joe_corpus if len(w)>3]
words_chandler=[w for w in chandler_corpus if len(w)>3]

我将进一步使用 nltk lemmatizer 来查找所有单词的词干作为有效单词。请注意,我在避免使用 portstemmer,因为它也会产生一些无效单词。

WNLemma=nltk.WordNetLemmatizer()
stem_freq_words_rach=[WNLemma.lemmatize(t) for t in words_rach]
stem_freq_words_ross=[WNLemma.lemmatize(t) for t in words_ross]
stem_freq_words_chandler=[WNLemma.lemmatize(t) for t in words_chandler]
stem_freq_words_mon=[WNLemma.lemmatize(t) for t in words_mon]
stem_freq_words_phoebs=[WNLemma.lemmatize(t) for t in words_phoebs]
stem_freq_words_joe=[WNLemma.lemmatize(t) for t in words_joe]

接下来,我将添加所有单词,并为每个角色创建一个口语单词字符串,以提供给 IBM Watson NLU 服务进行情感分析。

s_rachel=""
for w in stem_freq_words_rach:
   s_rachel=s_rachel+' '+ws_ross=""
for w in stem_freq_words_ross:
   s_ross=s_ross+' '+ws_phoebs=""
for w in stem_freq_words_phoebs:
   s_phoebs=s_phoebs+' '+ws_joe=""
for w in stem_freq_words_joe:
   s_joe=s_joe+' '+ws_chandler=""
for w in stem_freq_words_chandler:
   s_chandler=s_chandler+' '+ws_mon=""
for w in stem_freq_words_mon:
   s_mon=s_mon+' '+w

然后,我会调用沃森 NLU 服务,并传递每个角色的口语单词进行情感分析,如下所示。

import json
from ibm_watson import NaturalLanguageUnderstandingV1
from ibm_watson.natural_language_understanding_v1 import Features, EmotionOptions
import pandas as pd
import matplotlib.pyplot as pltdicti={}
natural_language_understanding = NaturalLanguageUnderstandingV1(
        version='2019-07-12',
        iam_apikey='please put your api key here',
        url='[https://gateway.watsonplatform.net/natural-language-understanding/api'](https://gateway.watsonplatform.net/natural-language-understanding/api'))#rachelresponse = natural_language_understanding.analyze(
    text=s_rachel,
    features=Features(emotion=EmotionOptions())).get_result()
print("Rachel")
print("======================================")
dicti["Rachel"]=response["emotion"]["document"]["emotion"]
print(json.dumps(response["emotion"]["document"]["emotion"], indent=2))#ross
response = natural_language_understanding.analyze(
    text=s_ross,
    features=Features(emotion=EmotionOptions())).get_result()
dicti["Ross"]=response["emotion"]["document"]["emotion"] #monica
response = natural_language_understanding.analyze(
    text=s_mon,
    features=Features(emotion=EmotionOptions())).get_result()
dicti["Monica"]=response["emotion"]["document"]["emotion"] #phoebe
response = natural_language_understanding.analyze(
    text=s_phoebs,
    features=Features(emotion=EmotionOptions())).get_result()
dicti["Phoebe"]=response["emotion"]["document"]["emotion"] #chandler
response = natural_language_understanding.analyze(
    text=s_chandler,
    features=Features(emotion=EmotionOptions())).get_result()
dicti["Chandler"]=response["emotion"]["document"]["emotion"] #joey
response = natural_language_understanding.analyze(
    text=s_joe,
    features=Features(emotion=EmotionOptions())).get_result()
dicti["Joey"]=response["emotion"]["document"]["emotion"]print(json.dumps(dicti, indent=2))

我将输出转换成 dataframe 并打印如下。

df = pd.DataFrame(dicti)
df

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sentiment density distribution for each of the Characters

为了更好的形象化,我绘制了如下图。

df.transpose().plot(kind='bar')
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Bar chart for sentiment density distribution for each of the Characters

从上面的条形图推断

根据情感密度分布,节目中的所有角色都非常相似。这可能是他们相处融洽、形影不离的原因。这些角色充满了欢乐、悲伤和厌恶:)。

然后,我可视化一个饼图,以便更好地理解这些角色,如下所示(代码可以为每个角色复制—这里只为 Rachel 提供)。

colors = ['b', 'g', 'r', 'c', 'm']
labels = ['Anger', 'Disgust', 'Fear', 'Joy', 'Sadness']
explode = (0.2, 0.2, 0.2, 0.2, 0.1)
plt.pie(df.Rachel, colors=colors, labels=labels,
explode=explode, autopct='%1.1f%%',
counterclock=False, shadow=True)
plt.title('Sentiment Density Index for Rachel')
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从上面的饼状图推断

最平衡的角色是钱德勒,其次是瑞秋和莫妮卡。菲比和乔伊彼此非常相似,罗斯、瑞秋和莫妮卡也是。

我还引入了一个新的变量“快乐商数”,来计算每个角色的快乐相对于其他情绪的比例。

我们可以用类似的方式来评估所有其他情感的这个商。

happy_quotient_Rach=df.Rachel.joy/df['Rachel'].sum()
happy_quotient_Ross=df.Ross.joy/df['Ross'].sum()
happy_quotient_Joey=df.Joey.joy/df['Joey'].sum()
happy_quotient_Monica=df.Monica.joy/df['Monica'].sum()
happy_quotient_Phoebe=df.Phoebe.joy/df['Phoebe'].sum()
happy_quotient_Chandler=df.Chandler.joy/df['Chandler'].sum()

让我们看一个散点图,找出最幸福的人物。

x = ['Rachel','Ross','Joey','Monica','Phoebe','Chandler']
y = [happy_quotient_Rach,happy_quotient_Ross,happy_quotient_Joey,happy_quotient_Monica,happy_quotient_Phoebe,happy_quotient_Chandler]colors = np.where(df_hq.Happiness_Quotient > 0.25, '#ff748c', '#497087')
plt.scatter(x,y,s=120, c=colors)
plt.show(

情商的曲线图如下。

x_happy = ['Rachel','Ross','Joey','Monica','Phoebe','Chandler']
y_happy = [happy_quotient_Rach,happy_quotient_Ross,happy_quotient_Joey,happy_quotient_Monica,happy_quotient_Phoebe,happy_quotient_Chandler]
colors = ['r','g','b','y','cyan','m']
plt.scatter(x_happy,y_happy,s=120, c=colors)
plt.title('Happiness Quotient for the Characters')
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从上面的散点图推断

最幸福的角色依次是:罗斯、乔伊、菲比、瑞秋、钱德勒

最悲伤的角色依次是:菲比、乔伊、罗斯、莫妮卡、瑞秋、钱德勒

最恶心的角色依次是:钱德勒、莫妮卡、罗斯、乔伊、菲比、瑞秋

最害怕的角色依次是:瑞秋、莫妮卡、钱德勒、乔伊、菲比、罗斯

最愤怒的角色依次是:菲比、乔伊、罗斯、瑞秋、莫妮卡、钱德勒

备注

这是一次尝试,通过网上的文字记录来了解角色的情感,看看我是否能把它与我在观看这部剧时对这些角色的感受联系起来。

我会继续研究这个数据集,希望很快能有更多的见解。

有效地预处理文本数据第 2 部分:实现

原文:https://towardsdatascience.com/sentiment-analysis-on-raw-text-using-amazon-imdb-and-yelp-f2547c805f1?source=collection_archive---------16-----------------------

这篇文章是我之前关于文本预处理的文章的直接延续。这是一些重要的文本预处理步骤的实际实现,这些步骤在输入到机器学习模型之前使用。我没有通过编写脚本来使用传统的预处理和学习方法,而是使用了一个叫做 Knime 的工具。

数据选择和分析

该数据集可在 UCI 数据库上获得,标题为“情感标签句子数据集”。数据集基本上被收集并手工标记为积极或消极情绪。

数据集由三个原始文本文件组成,分别命名为 amazon _ cells _ labelled.txt、imdb _ labelled.txt 和 yelp _ labelled.txt。每个文件包含 1000 个带标签的评论及其对应的标签,这些标签可以是 0,表示负面情绪,1 表示正面情绪。

在大规模了解单个客户的情绪/行为时,情绪分析是一个主要问题。文本是人类用来传递信息的最广泛的一种交流方式。该消息可以是一些信息、反馈、警告或其他人可以理解的任何类型的信息。当遇到大量用户反馈的情况时,几乎不可能手动检查每条记录,然后试图理解数百万条反馈的整体语义。换句话说,人类几乎不可能总结数百万条信息。因此,抽取文本的情感是解决上述问题的关键部分。最简单的情感分析形式是,我们需要判断某段文字对某个主题是正面情感还是负面情感。

在文本分析领域中,这种需要将消息分类为两个或更多不同类别的问题被称为分类问题。

分类是监督学习的一部分,在监督学习中,我们不仅可以获得数据集实例,还可以获得特定实例所属的标签或类。

在这项总体任务中,我们将回答以下基本数据挖掘问题:

1.)对于原始文本形式的可用数据,定义的预处理步骤是什么?

我们将看到预处理和清理文本与普通的数据预处理任务完全不同。存在依赖于语言的算法,这使得很难提出通用的文本预处理任务。在数据分析部分,将详细解释文本预处理步骤。

2.)通过文本提取什么样的特征?

我们有不同的方法来提取数字特征,如 TF-IDF、BoW 等,这些将在下面的文本挖掘部分进行解释。

现在,我们将看到有成千上万个不同的单词,这意味着我们将使用非常巨大的向量,我们的训练数据集矩阵将是一个非常稀疏的矩阵。

让我们看看稀疏矩阵是什么样的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 1: Bag of Words features with first 15 rows

经过预处理后,我们剩下 3035 个唯一项,这意味着每个向量将有 3035 个 1 和 0(大部分是 0)。

3.)说到情感分析,哪些分类技术是最强的?

这个问题没有简单的答案,但是,考虑到这是一个二元分类,我们应该期待逻辑回归是最好的结果生产者之一。除此之外,SVM 可以给出很好的结果,因为支持向量机在维数较高的地方更好。就神经网络而言,其架构的变化,即层数和神经元数量的变化,几乎会改变一切。简而言之,神经网络既可以是这项任务的最佳选择,也可以是最差的选择。

4.)什么样的聚类技术比较合适?

正如我们上面讨论的,数据非常稀疏,K-Means 聚类不适合这些场景。我们知道只有几个 1 和大多数 0,这意味着在 3035 维向量空间模型中,如果我们应用 K-Means,我们将得到一个没有太多差异的高密度集群。因此,我们将了解分层聚类是如何进行的。考虑到数据量,使用层次聚类将会产生一个非常复杂的树形图。

5.)整个数据中的整体候选子集看起来如何,意思是,数据呈现的核心主题是什么?

我们将在该报告的数据分析部分看到数据中最热门的关键词趋势。考虑到积极情绪和消极情绪的数量相等,可以预计会有很多混淆的关键词来描述积极情绪和消极情绪。

数据分析

由于缺乏结构,文本数据分析是最麻烦的任务之一。但是,我们将执行基本的文本和数据分析,以找到数据集的摘要。数据集是从三个不同公司的三个不同文件中读取的,在对数据进行任何分析之前,我们必须合并所有记录。这种数据合并在第一步中执行,如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 2: Reading and Concatenating multiple files

如果我们观察正类与负类的比率,我们看到在 3000 条记录中,1500 条对应于正类,1500 条对应于负类。在机器学习中,类的数量相等是更可取的,因为当类的数量不相等时,模型预计会变得有偏差。对于一个类,该模型将暴露给数据集的更多实例,并且该类的权重将会更高,最终,与其他类相比,该模型更有可能预测该类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 3: Row counts for each class

另一种重要的文本数据分析技术叫做词云,或者标签云。标签云很重要,因为它们不是一些具有可解释意义的图形或图表,相反,它们只是代表整个文本集合的基于关键字的总结,这样,我们就能够直接推断出讨论最多的趋势。这种分析被公司用来判断某个产品是否存在特定的问题。即使在竞选活动的数据收集期间,这些来自社交媒体账户的数据也是由这些机构收集的,最高发生趋势通过标签云可视化,以了解公众在大规模上真正谈论的是什么。

虽然数据集非常平衡,这对训练分类模型来说是一件好事,但是图 1 中一个值得注意的事情是数据的稀疏性。观点大多很短,在大多数情况下不超过一句话。这将是一项具有挑战性的任务,因为数据实例之间的决策边界将非常模糊,因此很难训练一个具有真正良好准确性的分类器。

考虑一下“书”这个术语。下面是一个饼图,显示了总评论中出现的术语的比率。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 4: Percentage of the term “book” appearing in the reviews

这说明 99.9%的行不包含“书”这个词,只有 0.1%的行/句包含“书”这个词。其他许多术语也有类似的情况。这种数据很难处理。虽然平衡的课程对我们来说是一个机会,但稀疏的数据集对我们来说是一个挑战,因为评论通常不是非常详细。

我们对整个数据集应用了层次聚类来得到一个树状图,这实际上是一个非常紧凑的树。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 5: Dendogram of the entire corpus

虽然很难判断树突图中到底显示了什么,但我们可以看到密集的区域,并知道数据中存在某些“分组”,这是因为评论来自不同的语言领域。

文本挖掘

我们只有文本评论和它们的情感标签,因此如果没有任何文本挖掘方法,这个问题是不可能解决的。如果没有任何实体文本挖掘方法,我们将无法计算数字特征,没有这些数字特征,就不会有训练好的分类器。

该任务的文本预处理有 9 个主要步骤,如下所示:

  • 去掉标点符号,因为它们在文本数据中表现为噪音,因为它们没有特定的语义。
  • 去掉数字和数字,因为我们想进行定性分析(肯定或否定),而不是任何涉及数字的定量分析。
  • 删除所有少于或等于三个字符的单词,因为这些单词可能是停用词,也可能是充当俚语的单词。
  • 删除 and、or、of、is、am、had 等停用词。停用词是如此普遍,并且持有如此少的语义信息,以至于它们的移除是有利的,因为它不仅降低了向量空间模型的维度,而且在大多数情况下增加了分类的准确性。
  • 将整个文本转换为小写,因为计算机会将“awesome”和“Awesome”解释为两个不同的术语,因为小写和大写“A”和“A”的编码不同。
  • 应用波特·斯特梅尔。词干提取是一个重要的阶段,因为它将单词或术语还原到它们的根源。例如,术语“更快”被转换成“快”,“推荐”转换成“推荐”,“吃”转换成“吃”,等等。这有助于保留句子的语义,同时简化重复。
  • 按文档对术语进行分组。
  • 从分组的术语中提取关键字,因为我们不希望每隔一个单词都被限定为一个特征。我们只考虑数据集中最重要的术语,并且只保留合格的关键字术语。
  • 将提取的关键词转换成稀疏向量,或者我称之为“矢量化”。

向量化是一个重要的决定,因为将英语单词转换成向量,使得它们的语义可以通过非常高维的数字向量来表示,这是一个有点棘手的过程。对于我们的具体问题,我们可以选择使用 TF-IDF 特性,它代表 term frequency-InvertedDocumentFrequency。当我们要开发一些信息检索系统时,这些类型的特征是首选的,在这些系统中,不仅存在,而且术语存在的次数以及术语(单词)存在的文档数量也很重要。TF-IDF 特性基本上为稀有词提供较高的值,为常用词提供较低的权重值。我们将计算的特征被称为 BoW(单词包)特征,它们背后的思想是,我们将一个文档(在我们的例子中,是一篇评论)视为一个集合,或者说,一个由不同术语(单词)组成的“包”。一个单词要么存在于文档中,要么不存在。弓的整个概念是基于非常大的二进制向量。每个单词代表一个唯一的维度,因此如果在 D 个文档的整个集合中有 W 个唯一的单词,那么每个文档将被表示为 W 维向量。考虑四个单词的词汇表,比如“阿尔法、贝塔、查理和德尔塔”。现在,每个单词或术语都有一个索引。假设这些索引是按照字母顺序排序的。在这种情况下,术语“alpha”位于索引 0,“beta”位于索引 1,依此类推。现在,如果我们想要表示一个文档,上面写着“alpha beta delta delta”,那么它可以表示为一个四维向量[1,1,0,1]。请注意,由于“charlie”不是文档的一部分,并且术语“charlie”的索引是 2(从零开始的索引),这意味着向量中的第二个索引仍然是 0,而其他索引是 1。另一个例子可以是文档“alpha alpha charlie”,它将被表示为[1,0,1,0]。

上述任务的总体流程如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 6: Text preprocessing flow

我们的数据集是关于常见产品和电影的评论。因此,让我们看看我们的数据集中前 250 个术语是什么,然后我们可以讨论用户通过他们的反馈和评论集体传达了什么样的信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 7: Tagcloud of the entire dataset

因此,正如我们所见,“电影”、“影片”、“电话”、“食物”、“时间”、“推荐”、“爱情”、“失望”,这些术语主宰了数据集。我们可以很容易地推断出,大多数人都在谈论手机,通过查看标签云,我们可以估计评论数据集中产品的业务流。

预处理非结构化数据是数据科学和机器学习中最困难的任务之一,因为没有特定的统计准则可用。一旦我们完成了所有步骤,我们只需要将数据分为训练和测试,并对数据应用一些机器学习,以查看基于我们所做的预处理的模型有多好。整个 Knime 工作流程的视图(有点混乱)如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 8: Overall view of the Knime workflow

我们可以看到不同的机器学习模型,如朴素贝叶斯、多层感知器、SVM、逻辑回归和决策树,以及它们相应的学习器、预测器和评分器节点。作为一个小小的提示,我将给出一个简短的表格,按照分类器的准确度进行分类。我们可以使用其他更高级的评估指标,如 precision、recall 和 F1-Score,但是由于这两个类的行数相当相同,因此只根据准确性来评估模型的性能并不是一个坏主意。

对于二进制分类问题,朴素贝叶斯的表现不到 50%,这比扔硬币还糟糕。总的来说,模型性能不是很好,但是对于一些不同的、更高级的文本矢量化工具,如 Word2Vec、GloVe、BERT 等,还有很大的改进空间。

结论

  1. 如果你不是一个编码爱好者,有一些令人惊讶的工具可以让你开始学习数据科学和机器学习。
  2. 在处理非结构化数据时,预处理步骤的选择以及这些步骤的顺序可能很重要(请参考上一篇文章,以了解更多关于那篇文章的信息)。
  3. 在某些情况下,最简单的解决方案可以胜过高度复杂的解决方案,所以永远不要低估简单的解决方案。
  4. 尝试执行情感分析时,TF-IDF 不是最佳选择。

使用 Twitter 对 Swachh Bharat 进行情感分析

原文:https://towardsdatascience.com/sentiment-analysis-on-swachh-bharat-using-twitter-216369cfa534?source=collection_archive---------6-----------------------

情感分析是提取人们对特定问题、品牌、方案等的看法。,(感悟)来自文字资料。它的应用范围很广,从品牌监控、产品评论分析到政策制定。在本文中,我们对带有 Swachh Bharat 标签的推文进行情感分析。这个项目的完整代码可在这里获得。

本文分为以下几个部分。

  1. 执行情感分析的不同方法
  2. 收集数据
  3. 将有用的数据转换为 CSV
  4. 删除重复的行和不必要的列
  5. 清理推文
  6. 停止单词删除
  7. 词汇化和词干化
  8. 数据可视化
  9. 将推文文本矢量化
  10. 从 sklearn 实现分类器
  11. 实施 Gensim 模型
  12. 摘要

执行情感分析的不同方法

有两种主要的方法来执行情感分析——基于词典的方法或使用机器学习模型。任何基于词典的方法基本上都是使用带有语义分数的单词词典来计算推文的最终极性。例如,考虑句子“我爱这部电影,尽管第二部分有点慢”。现在,像这样的每个单词将被分配一个(总)情感分数。

“I:0, love:0.750, this:0.0, movie:0.0, eventhough:0.0 the:0.0 second :0.0,part:0.0,is :0.0,boring:-0.250”

正的分数表示这个词是正面的,负的分数表示它是负面的。现在,如果我们把这句话的所有分数加起来,将是-0.500,这是一个积极的情绪。所以这条推文会被贴上正面的标签。可用的重要词库资源有- SentiWordNetTextBlobAfinnMPQA(多视角问答)主观性词库和模式。我用 SentiWordNet 使用这种词典方法来标记我的推文(稍后解释)。

第二种,机器学习方法,在预处理数据之后,使用分类器将问题作为文本分类任务来处理。我们遵循后一种方法,这将被详细解释。

关于该任务所需的工具

有许多用于文本处理和分类的库——NLTK(综合和艰难的学习曲线)、TextBlob(易于使用,适合初学者)、Spacy(行业工作的理想选择)等等。我选择 NLTK,因为它提供了许多支持库来实现许多文本处理技术

开始吧!

收集数据

现在我需要文字资料来表达人们对 Swachh Bharat 的看法。很少有选择是使用 Reddit API、脸书 API、Twitter API,以及从网页中抓取数据。我决定使用 twitter API 来收集关于 Swachh Bharat 的推文,因为许多人认为 twitter 是一个巨大的心理数据库。这个项目的推文是使用 python 中的 Tweepy 库从 Twitter 数据库收集的。为了访问推特,你必须创建一个推特开发者账户。有不同类型的开发人员帐户:标准搜索(免费),高级(付费)和企业(付费)。API 的功能或可访问性从标准帐户增加到企业帐户。例如,通过标准帐户,你可以访问过去七天的推文,而这是 30 英镑的高级帐户。为了创建账户,你必须提供核心用例的细节、意图、使用的商业目的、关于你计划进行的分析的细节以及方法或技术。我建议在第一次尝试中提供尽可能多的细节(也可以添加与你的项目相似的网页链接或项目的主题,只要你想澄清事情),否则你必须写长邮件一遍又一遍地解释相同的内容,以防他们需要更多的信息。Twitter 团队将彻底审查你的申请。这篇是一篇关于 Twitter 数据挖掘的好文章。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你的信息是完整的,通常不到一天就可以收到批准邮件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

之后,您需要在他们的界面中创建一个新的应用程序,并提供其描述(如下),该描述将生成 API 密钥、API 密钥、访问令牌和访问令牌密钥,我们将使用这些信息通过终端登录。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Creating a new application

现在让我们使用 tweepy 来验证我们的详细信息。AppAuthHandler()函数。用您的身份验证详细信息替换“*”。

import tweepy
API_KEY="*********************"
API_SECRET="*************************"
ACCESS_TOKEN="*******************************"
ACCESS_TOKEN_SECRET="******************************"
auth = tweepy.AppAuthHandler(API_KEY, API_SECRET)
auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
api = tweepy.API(auth)
print(api.me().name)

如果验证成功,您应该会看到打印出的帐户名称。

IAmSai

认证之后,我们就可以下载推文了。我们使用 API.search() 方法来获取 tweets。使用 Tweepy 搜索 Tweepy 有两种主要方式——按标签(或关键字)搜索和按 Tweepy 的 id 搜索(每个 Tweepy 的 id 都是唯一的)。第二种方法在你需要收集所有 tweet 的 id 时很有用(比如,你想收集关于给定 id 的去货币化的 tweet。这些 id 将由那些以前收集过关于该主题的数据的人给出)。因为我没有任何 id,所以我使用第一种方法。

search_query="#SwachhBharat"
new_tweets = api.search(q=search_query,count=tweetsPerQuery,lang="en",tweet_mode='extended')
auth = tweepy.AppAuthHandler(API_KEY,API_SECRET)
api = tweepy.API(auth,wait_on_rate_limit=True,wait_on_rate_limit_notify=True)
fName = 'sb_04_08_19.txt' # where i save the tweets

上面的代码片段中没有给出几行重要的代码。详细代码请看

我们使用关键字“#SwachhBharat”进行搜索。后来,在清理数据时,我意识到带有标签的推文——“# myclean India”和“#SwachhBharatUrban”也可以用来搜索关于 Swachh Bharat 的推文。我们使用 AppAuthHandler(第三行)而不是最常用的-OAuthHandler 来为授权API。OAuthHandler 允许每个 15 分钟窗口最多 180 个请求(每个请求最多 100 条 tweets)。所以我们只能在 15 分钟内获得 18000 条推文。但是 AppAuthHandler 有其最大请求速率限制,即每个请求 450 条和 100 条 tweets。因此,它有助于在 15 分钟内获得 45,000 条推文。此外,我使用了扩展 tweet 模式(第二行),以确保我们获得完整的 tweet,而不是被截断的 tweet。下载后,我们将把推文保存在一个文本文件中(或者,我们也可以把它们保存在一个. json 文件中)。我又重复了几次以上的过程,以便以后收集更多的 tweet(两次数据收集之间的间隔超过 7 天,否则我们会得到很多重复的 tweet)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Downloading the tweets

将有用的数据转换为 CSV

这是我最初很难理解的部分,因为我从未使用过 API 和 JSON。这个文本文件很大,大约有 1100 页的信息。在“sb.txt”(文本文件)中,推文是 JSON (JavaScriptObjectNotation)格式的。看一看它。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Data is full of many JSON objects

只需扫一眼,您就可以看到有许多特性(对象)对我们的任务来说并不重要,比如元数据、索引、屏幕名称。所以我浏览了这个页面,找出我的任务可能需要的对象。我决定使用这些对象——full _ text(推文的全文)、retweet_count(推文的)、favorite_count(推文的)、geo(地理位置)、coordinates(地点的纬度和经度坐标)、place(推文的来源)、follower_count(推文用户的)、created_at(推文的时间和日期)、id_str(推文的字符串格式的 id)。我将上述对象保存在我的 CSV 文件中,并丢弃其余的。

inputFile='sb_04_08_19.txt'
tweets = []
for line in open(inputFile, 'r'):
    tweets.append(json.loads(line))
for tweet in tweets:
    try:
        csvWriter.writerow([tweet['full_text'],tweet['retweet_count'],tweet['user']['followers_count'],tweet['favorite_count'],tweet['place'],tweet['coordinates'],tweet['geo'],tweet['created_at'],str(tweet['id_str'])])
        count_lines+=1
    except Exception as e:
        print(e)

上面给出了从文本文件转换为 CSV 文件的几行重要代码。请参见这个以了解更多信息。我们创建一个 tweets 列表,从文件中读取每一行(第一个 for-loop)。然后,我们使用 csvWriter.writerow()将每个 tweet 的必要信息写入 CSV 文件。而且我们只收集上面提到的对象。

让我们尝试在 Jupyter 笔记本中加载 CSV 文件。有必要在 read_csv()函数中将编码参数设置为“unicode_escape ”,因为一些推文也包含表情符号,这会给默认编码带来困难。

import pandas as pd
df = pd.read_csv('somall.csv', encoding = 'unicode_escape')
df.head(5)

看一下输出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

删除重复行

让我们查看并删除重复的行(如果有的话)。有两种类型的重复——所有列都具有相同值的重复(当 tweet-collector 再次收集相同的 tweet 时会发生这种重复)和 tweet 具有相同文本的重复(当两个或更多用户发布相同的 tweet 时会发生这种重复。)

print(len(df.index))#14195
serlis=df.duplicated().tolist()
print(serlis.count(True))#112
serlis=df.duplicated(['full_text']).tolist()
print(serlis.count(True))#8585

我们可以看到,在 full_text 列中有 112 个重复行和 8585 个重复行,行重复是 full_text 重复的一个子集。所以我们删除了所有重复的行。

df=df.drop_duplicates(['full_text'])

起初,我没有注意到重复。因此,当使用文本分类器时,它们给我的准确率高达 99.54%,这并不好。

删除不必要的列

似乎有几个像“地点”、“地理”这样的特征有更多的非数字(NaN)值。让我们检查一些选定的列中有多少空行

print(df['geo'].isna().sum())
print(df['place'].isna().sum())
print(df['coordinates'].isna().sum())

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们的数据集中总共有 14,195 行。我们看到 14191 行地理列是空的。“位置”和“坐标”中的空行也很高(13951 和 14191)。所以我们把这些列和‘id _ str’(tweet 的 id)一起删除了,因为 tweet id 对我们来说用处不大。虽然我们在上下文中没有使用 retweet_count、user_followers_count、favorite_count,但是我们没有删除它们,因为它们可以用于其他任务(比如估计 tweet 的受欢迎程度,这可以用于为 tweet 分配权重)。

df=df.drop([‘place’,’coordinates’,’geo’,’id_str’],axis=1)
df.head(5)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

First five rows of the dataset after dropping a few columns

清理推文

在一条推文的文本中,可能会有一些不必要的符号,这些符号对于我们的分析并不重要。所以让我们继续清理我们的推文。

让我们观察任何特定推文的全文。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

full text of a tweet at row number 22

正如我们所看到的,一些不必要的文本和符号被删除——用户名 _ 标签(如@_WeMeanToClean),转发符号(RT),标签(如#MyCleanIndia),网址(如 https://t.co/XK3ZReâ\x80),数字和标点符号。一些有意义的标签传达了意思,在单词被分割成有用的部分后可以有一些情绪在里面(比如#ILoveSwachhBharat)。因此,不是删除所有以 hashtag 符号开头的单词,而是只删除’ # '符号。我们使用 python 中的 re 模块来执行文本清理。re.sub()函数搜索一个模式并用我们指定的文本进行替换。我们用空白字符替换所有这些符号。

import re
for i in range(len(df)):
    txt = df.loc[i]["full_text"]
    txt=re.sub(r'@[A-Z0-9a-z_:]+','',txt)#replace username-tags
    txt=re.sub(r'^[RT]+','',txt)#replace RT-tags
    txt = re.sub('https?://[A-Za-z0-9./]+','',txt)#replace URLs
    txt=re.sub("[^a-zA-Z]", " ",txt)#replace hashtags
    df.at[i,"full_text"]=txt

现在,我们可以看到我们的推文看起来很干净。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A tweet after cleaning

词性标注和情感标注

我们已经完成了文本数据的基本清理工作。在 ML 算法中,我们将实现 tweet 的“full_text”作为预测变量(如果我们想要预测 tweet 的影响,可以使用的其他变量是 retweet-count、favorite-count,但这不是我们当前任务的一部分)。很明显,我们需要为我们的数据创建目标变量(情感得分)。为此,我们使用 SentiWordNet。 SentiWordNet 是一个增强的词汇资源,专为支持情感分类和观点挖掘应用而设计。它有一个很大的词类标注英语单词及其情感的语料库。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Predicting sentiment of few words using SentiWordNet-An example

和上面的例子一样,SWN 给出了每个单词的 pos_score 和 neg_score。pos_score 越高,这个词越正面。我们使用这些分数的简单线性求和(我们将 tweet 中所有单词的 pos_score 相加以形成 pos_total,以类似的方式,我们获得 neg_total。然后我们把这两个加起来得到 sent_total)并把一个句子标注为正(1)如果它(sent_total)大于 0,负(-1)如果它小于 0,中性(0),否则。你可能已经发现,为了使用 SWN,我们需要找到我们推文的词性标签。nltk 的 pos_tag 特性可以帮助我们标记文本,但是它并没有被简化(除了名词、代词、形容词、动词之外,它还可以用更多的标签来标记文本,比如 adposition、连接词、限定词等等。,).但是 SWN 只接受简化的标签。所以我们尝试使用 nltk 库中的 map_tag 函数来简化标签。

for i in range(len(df_copy.index)):
        text = df_copy.loc[i]['full_text']
        tokens = nltk.word_tokenize(text)
        tagged_sent = pos_tag(tokens)
        store_it = [(word, map_tag('en-ptb', 'universal', tag)) for word, tag in tagged_sent]

第二行将 tweet 文本转换成标记,这些标记将在以后用它们各自的词性进行标记。然后,我们将单词和标签存储在 store_it 列表中。该列表随后将被传递给使用 SWN 的情感标签。

当使用 pos_tag()和简化的 POS-tag 进行标记时,推文的标签(“旁遮普省尼赫鲁·尤瓦·肯德拉的成员开展了挨家挨户的垃圾分类宣传活动”)如下所示。

Tagged Parts of Speech: [('a', 'DT'), ('door', 'NN'), ('to', 'TO'), ('door', 'VB'), ('waste', 'NN'), ('segregation', 'NN'), ('awareness', 'NN'), ('drive', 'NN'), ('was', 'VBD'), ('carried', 'VBN'), ('out', 'RP'), ('by', 'IN'), ('members', 'NNS'), ('of', 'IN'), ('nehru', 'JJ'), ('yuva', 'NN'), ('kendra', 'NN'), ('in', 'IN'), ('kapurthala', 'NN'), ('punjab', 'NN')]Tagged Parts of Speech- Simplified: [('a', 'DET'), ('door', 'NOUN'), ('to', 'PRT'), ('door', 'VERB'), ('waste', 'NOUN'), ('segregation', 'NOUN'), ('awareness', 'NOUN'), ('drive', 'NOUN'), ('was', 'VERB'), ('carried', 'VERB'), ('out', 'PRT'), ('by', 'ADP'), ('members', 'NOUN'), ('of', 'ADP'), ('nehru', 'ADJ'), ('yuva', 'NOUN'), ('kendra', 'NOUN'), ('in', 'ADP'), ('kapurthala', 'NOUN'), ('punjab', 'NOUN')]

然后,我们通过上面介绍中提到的方法来查找 tweet 的情感。请查看完整的代码以了解更多关于情感标签的信息。从 SWN 获得意见后,我们在我们的 CSV 中增加了三列——“积极得分”、“消极得分”、“发送得分”。tweet 的“pos_score”是 tweet 中所有单词的净正分,类似的还有“neg_score”。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Dataset after adding sentiment score for tweets

正面推文的值为 1(pos _ score > neg _ score),中性推文的值为 0(pos _ score = neg _ score),负面推文的值为-1(pos _ score<neg_score there=“” are=“” positive=“” tweets=“” neutral=“” and=“” negative=“” tweets.=“” i=“” also=“” used=“” class=“ae kl” href=“https://github.com/SivaAndMe/Sentiment-Analysis-on-Swachh-Bharat-using-Twitter/blob/master/textblob_sentiment_labeling.py” rel=“noopener ugc nofollow” target=“_blank”>text blob 和 Afinn 用于推文的情感分配)。结果如下:</neg_score>

TEXTBLOB:
Total tweets with sentiment: 5610
positive tweets: 2171
negative tweets: 591
neutral tweets: 2848AFINN:
Total tweets: 5610
positive tweets: 2551
negative tweets: 572
neutral tweets: 2487

来自每个情感的推文数量在每个分类器中的比例是一致的,这让我们对情感标签更有信心。此外,我们可以推断出大多数推文是积极的。

现在我们已经完成了情感标注,我们将进一步准备我们的文本数据,以馈入 ML 分类器。

停止单词删除

停用词是常用词,如 of、the、for 等。在我们的语境中,它们并没有给情感增加多少分量。此外,它们增加了数据的维度。所以我们使用 nltk 库删除了停用词(在下一部分)。

在将这些文本数据提供给 ML 算法之前,我们将它转换成向量(在本文的后面部分)。我们不希望相似的单词有不同的(向量)值。我们希望所有这些词都有相同的价值——“分发”、“分配”、“已分发”、“分发”,因为它们本质上表达了相同的意思。如果我们使用 nltk 模块执行词汇化和词干化,这(为相似的单词分配相同的值)可以更好地实现。

词汇化和词干化

词干化将单词缩减为它们的词干。词干提取算法主要是基于规则的。例如,他们把上面所有的单词“distribute”简化为“distribute”。一个词条解释器做了和斯特梅尔一样的事情,但是把这个词的语言学保持在上下文中。例如,以上所有的单词都将被浓缩为“distribute”。

from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
from nltk.stem import PorterStemmer
pstem = PorterStemmer()
lem = WordNetLemmatizer()
stop_words = stopwords.words('english')for i in range(len(df.index)):
     text = df.loc[i]['full_text']
     tokens = nltk.word_tokenize(text)
     tokens = [word for word in tokens if word not in stop_words]for j in range(len(tokens)):
         tokens[j] = lem.lemmatize(tokens[j])
         tokens[j] = pstem.stem(tokens[j])tokens_sent=' '.join(tokens)
     df.at[i,"full_text"] = tokens_sent

第三行删除 tokens-list 中的停用词。经过词汇化和词干化,我们最终用新的文本代替旧的文本。

值得注意的是,上述三个清理过程(停用词去除、词干化、词条化)在(情感标注)之前不执行,因为这样做会导致情感检测的不规则性。像“distribut”、“cleanin”这样的词在 SWN 的英语词汇语料库中是找不到的,因此 SWN 没能检测出这些词的正负分值。这使得只有一部分数据集的推文标有情感分数。我们还使用 nltk 库将所有 tweets 转换成小写。

数据可视化

我们使用 WordCloud 来表示每个情感中的大多数单词。为此,我们将所有带有正标签的 tweets 文本相加,形成一个字符串,并将该字符串表示为 pos_string。对于负面和中性文本,我们也遵循同样的方法。

for i in range(len(df_copy.index)):
    if(df_copy.loc[i]["sent_score"]==1):
        pos_text+=df_copy.loc[i]["full_text"]
    elif(df_copy.loc[i]["sent_score"]==-1):
        neg_text+=df_copy.loc[i]["full_text"]
    else:
        neut_text+=df_copy.loc[i]["full_text"]

文本表示使用 python 中的 WordCloud 模块生成,并使用 matplotlib 绘制。

list_text = [pos_text,neg_text,neut_text]
for txt in list_text:
    word_cloud = WordCloud(width = 600,height = 600,max_font_size = 200).generate(txt)
    plt.figure(figsize=(12,10))# create a new figure
    plt.imshow(word_cloud,interpolation="bilinear")
    plt.axis("off")
    plt.show()

我们应该记住,单词之前已经被词干化和词条化,所以我们可能无法看到少数几个单词的完整单词。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Positive sentiment WordCloud

如你所见,标签由正面文本 Wordcloud 中的重要单词组成。这很直观,因为我们没有从文本中完全删除标签。虽然是一个印地语单词,但“swachh”(一个肯定的词)在这里经常出现。还有其他有用的词,如垃圾分类、垃圾收集、清洁等。,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Neutral sentiment WordCloud

在中性词 Cloud 中,除去少数标签,我们可以看到许多中性词,如-零件、街道、道路、周围环境、实习等。,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Negative sentiment WordCloud

停止乱扔垃圾,排水回来,排水是云的几个负面词汇,我们也可以看到它包含了许多其他情绪的词汇。

拆分数据

我们使用 nltk 库中 model_selection 模块的 train_test_split 函数将数据分为训练集、验证集和测试集。划分如下— 90%的训练数据,5%的验证数据,5%的测试数据。更多的数据用于训练,记住推特的数量更少。

import sklearn
from sklearn.model_selection import train_test_split
SEED=4
x = df.full_text
y = df.sent_score
x_train,x_val_test,y_train,y_val_test = train_test_split(x,y,test_size=0.1,random_state=SEED)
x_val,x_test,y_val,y_test = train_test_split(x_val_test,y_val_test,test_size=0.5,random_state=SEED)

将推文文本矢量化

在我们实现不同的 ML 文本分类器之前,我们需要将文本数据转换成向量。这是至关重要的,因为算法期望数据是某种数学形式,而不是文本形式。Quora 的这个回答解释了为什么转换到向量空间是必要的。这里,我们实现了来自 sklearn- Count 矢量器和 Tfidf 矢量器的两个矢量器。他们都属于词汇袋模式。

计数矢量器计算一个单词在文档中出现的次数(在每个 tweet 中),并使用这个值作为它的权重。为了形象化,向量中的列(矢量化后)由所有 tweet 中的所有不同单词组成,每行包含 tweet。计数器矢量器给我们一个稀疏矩阵(填充了许多零)作为矢量。

from sklearn.feature_extraction.text import CountVectorizer
cv=CountVectorizer(decode_error='ignore',lowercase=False,max_features=11)
x_traincv=cv.fit_transform(x_train.values.astype('U'))

让我们来看看 CountVectorizer 中的热门词(在所有推文中出现频率最高的词)。见这个的代码可视化顶词。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Count Vectorizer-Top words

让我们也实现 Tfidf 矢量器。TF-IDF 代表“术语频率-逆文档频率”。分配给标记的权重是术语(单词)频率和单词的文档频率的倒数的乘积。因此,如果一个词在 tweets 中出现得越频繁,它在这个矢量器中的重要性就越低(IDF-weight)。

from sklearn.feature_extraction.text import TfidfVectorizer
tf=TfidfVectorizer(decode_error='ignore',lowercase=False,max_features=11)
x_traintf=tf.fit_transform(x_train_copy.values.astype('U'))

Tfidf 的热门词汇是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Top words- Tfidf Vectorizer

对比 CV 和 Tfidf 中的 top 词,我们看到虽然词是一样的,但是顺序和频率不同。此外,Tfidf 有频率的小数值,而 CV 只有整数值。

N-grams

简单来说,n-grams 是我们在文本(tweets)中可以找到的所有相邻单词的组合。句子“我喜欢玩具”的所有可能组合:单字母词-(“我”、“喜欢”、“玩具”)、双字母词-(“我喜欢”、“喜欢玩具”)、三字母词-(“我喜欢玩具”)。“Swachh”这个词后面更常跟“Bharat”。因此,bi-grams 为我们提供了“Swachh Bharat”以及“Swachh”和“Bharat”。CV 和 Tfidf 都给出了一个名为 ngram_range 的参数。ngram_range as (1,1)表示一元模型,(1,2)表示二元模型,(1,3)表示三元模型等等。我们用 CV 和 Tfidf 实现了 uni、bi 和三元模型,并观察它们中的哪一个给出了更高的准确度分数。

从 sklearn 实现分类器

在对我们的推文进行矢量化之后,我们就可以开始实施分类算法了。我们要实现的分类器是-朴素贝叶斯模型(MultinomialNB,BernoulliNB,)线性模型(LogisticRegression,RidgeClassifier,PassiveAggressiveClassifier,感知器),集成模型(RandomForest 分类器,AdaBoostClassifier)和 SVM 模型(LinearSVC)。我们使用精确度分数来衡量模型的性能(精确度分数、召回和混淆矩阵也被计算)。

使用 sklearn 中的 cross_validate 模块,对每个分类器执行 K-fold 交叉验证,以验证模型性能的一致性。折叠数设为 10,记录交叉验证分数的平均值和标准偏差。训练每个分类器所花费的时间也使用 time.time()函数来测量。之后,结果将存储在 CSV 文件中。下面给出了几行重要的(不是全部)代码。完整代码请看

classifiers = [MultinomialNB(),BernoulliNB(),LogisticRegression(),LinearSVC(),AdaBoostClassifier(),RidgeClassifier(),PassiveAggressiveClassifier(),Perceptron(),RandomForestClassifier()]
**for clf in classifiers**:     
 model = make_pipeline(vec,clf)#vec is CV or Tfidf
           model.fit(x_train.values.astype('U'),y_train.values.astype('U'))
 labels = model.predict(x_val_copy.values.astype('U'))
 ac = accuracy_score(y_val_copy.values.astype('U'),labels)
 kfold = KFold(n_splits=10,shuffle=False,random_state=None)
 results = cross_validate( model,x_train_copy.values.astype('U'),   y_train_copy.values.astype('U'),cv=kfold)

            data.append([vec_gram,clf_names[i],ac,crossval_train_score_mean,crossval_test_score_mean,crossval_train_score_std,crossval_test_score_std, end-start])
            i+=1
d = pd.DataFrame(data,columns=['Vec_Gram','Classifier','Ac','crossval_train_score_mean','crossval_test_score_mean','crossval_train_score_std','crossval_test_score_std','Time.2'])
d.to_csv('all_clfs.csv')

结果如下。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Results of all classifiers using Count Vectorizer, Tfidf Vectorizer, each with uni, bi, and trigrams.

在上图中,“Ac”代表准确度分数,“cv_1”表示带有 unigrams 的 CountVectorizer。PassiveAggressiveClassifier(tfi df-bigrams)和 LinearSVC(Tfidf-trigrams)给出了 83.5714%的最高准确度。但是前者只需要 4.5 秒就可以训练好,而后者需要 18 秒。在交叉验证均值和标准差方面,LinearSVC 似乎更好。值得注意的是,我们的数据集是不平衡的——正面和负面的推文比中性推文更多。因此,在这种情况下,准确性分数可能会导致我们得出错误的结论。为了避免这种情况,我们还使用了具有平衡类权重的随机森林分类器。该分类器的平均准确率为 74.94%,最高准确率为 78.21%。

实施 Gensim 模型

我们已经使用单词袋模型(CV 和 Tfidf)对文本文档进行数字表示。从数学上来说,这是一个非常简单的方法。在这种方法中,单词之间的语义关系没有被保留。说,一句话有四个字:国王,王后,女人,男人。在 BoW 模型中,这些单词中的每一个都被唯一地分配了 id。因此,单词“king”可能更接近于“woman”而不是“queen”。因此,我们需要一个复杂的模型来保存单词之间的关系,从而给出文本的更好的数学表示。doc 2 vec(word 2 vec 的扩展)模型为我们做到了这一点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

It would be better if the words are semantically related as in above figure rather than being assigned some random ids

Doc2Vec 算法来自 python 中的 Gensim 库。Gensim 是一个免费的 Python 库,旨在尽可能高效地从文档中自动提取语义主题。我们实现了 doc 2 vec-DBOW(Distributrb Bag of Words)、DMC(Distributed Memory Concatenated)、DMM(Distributed Memory Mean)三种算法以及这三种算法的几种组合。稍后,我们使用所有这些模型来训练相同的分类器,就像我们在上面使用 sklearn 所做的那样。这些算法中的每一个要完成的步骤如下——连接所有数据集(训练、验证和测试),给所有推文(可以是随机标签)提供索引(标签),训练模型(DBOW、DMC 或 DMM ),从每个模型中获取向量。

x_all = pd.concat([x_train,x_val,x_test])

串联的第一步是可选的(即,我们可以仅使用训练数据集),但是建议串联以获得更好的结果。然后我们用‘d2v _ index’标记文本,其中‘index’是 tweet 索引。

def label_tweets(tweets,label):
    result = []
    prefix = label
    i=0
    for i, t in zip(tweets.index, tweets):
     t=str(t)
     result.append(LabeledSentence(t.split(), [prefix + '_%s' % i]))
  return result
x_all_w2v = label_tweets(x_all,'d2v')#x_all is obtained above by conatenating.

然后,我们训练这三个模型。

DBOW

cpu_count = multiprocessing.cpu_count()
model_dbow = Doc2Vec(dm=0,size=100,negative=5,min_count=2,alpha=0.065,workers=cpu_count,min_alpha=0.065)
model_dbow.build_vocab([each for each in tqdm(x_all_w2v)])for epoch in range(30):
    model_dbow.train(utils.shuffle([each for each in tqdm(x_all_w2v)]),total_examples=len(x_all_w2v),epochs=1)
    model_dbow.alpha-=0.002
    model_dbow.min_alpha = model_dbow.alphatrain_vecs_dbow = get_d2v_vectors(model_dbow,x_train,100)
val_vecs_dbow = get_d2v_vectors(model_dbow,x_val,100)

在第一行中,我们获得了并行处理的 CPU 数量。在定义了模型(第二行)之后,我们使用三个带标签的 tweets (x_all_w2v)来构建我们的词汇表。稍后,我们训练模型,在每次迭代中调整我们的学习率。请阅读文档以了解更多关于 Doc2Vec 函数的参数。

在定义了每个模型的特定参数后,以相同的方式训练其他两个模型。

DMC

cpu_count = multiprocessing.cpu_count()
model_dmc = Doc2Vec(dm=1,dm_concat=1,size=100,negative=5,min_count=2,alpha=0.065,workers=cpu_count,min_alpha=0.065)
model_dmc.build_vocab([each for each in tqdm(x_all_w2v)])for epoch in range(30):
    model_dmc.train(utils.shuffle([each for each in tqdm(x_all_w2v)]),total_examples=len(x_all_w2v),epochs=1)
    model_dmc.alpha-=0.002
    model_dmc.min_alpha = model_dmc.alphatrain_vecs_dmc = get_d2v_vectors(model_dmc,x_train,100)
val_vecs_dmc = get_d2v_vectors(model_dmc,x_val,100)

数字万用表

cpu_count = multiprocessing.cpu_count()
model_dmm = Doc2Vec(dm=1,dm_mean=1,size=100,negative=5,min_count=2,alpha=0.065,workers=cpu_count,min_alpha=0.065)
model_dmm.build_vocab([each for each in tqdm(x_all_w2v)])for epoch in range(30):
    model_dmm.train(utils.shuffle([each for each in tqdm(x_all_w2v)]),total_examples=len(x_all_w2v),epochs=1)
    model_dmm.alpha-=0.002
    model_dmm.min_alpha = model_dmm.alphatrain_vecs_dmm = get_d2v_vectors(model_dmm,x_train,100)
val_vecs_dmm = get_d2v_vectors(model_dmm,x_val,100)

我们保存了所有三个模型,以消除任何未来使用的重新培训。

model_dbow.save('d2v_model_dbow.doc2vec')
model_dmm.save('d2v_model_dmm.doc2vec')
model_dmc.save('d2v_model_dmc.doc2vec')
#AFTER THE FIRST TIME DON'T RETRAIN ALL THE MODELS,JUST LOAD THESE #like mod = model_dmm.load()

训练后,我们还使用 get_d2v_vectors()函数提取每个模型的向量,如下所示(还记得吗?这是我们使用 Gensim 模型的主要目的——获得文本数据的矢量化表示。下面的函数是在训练完模型后调用的(在上面的代码片段中)。

def get_d2v_vectors(model,corpus,size):
    vecs = np.zeros((len(corpus),size))
    n=0
    for i in corpus.index:
        prefix='d2v_'+str(i)
        vecs[n] = model.docvecs[prefix]
        n+=1
    return vecs

我们已经准备好了使用 doc2vec 模型的三种矢量表示。(train_vectors_dbow,train_vectors_dmc,train_vectors_dmm)。在将它们用于分类器之前,还有另一个有用的步骤要执行——连接这些向量(例如,DBOW+DMM)。为了获得更好的结果,Doc2vec 的作者建议采取这一步骤。我们使用 numpy.append()函数来连接这些向量。

#FUNCTION TO CONCAT 2-MODELS VECTORS..NO SPECIAL TRAINING IS REQUIRED
def get_concat_vectors(model1,model2,corpus,size):
    vecs = np.zeros((len(corpus),size))
    n=0
    for i in corpus.index:
        prefix='d2v_'+str(i)
        vecs[n] = np.append(model1.docvecs[prefix],model2.docvecs[prefix])
        n+=1
    return vecs

我们将 DBOW 与 DMM 以及 DBOW 与 DMC 连接起来。

train_vecs_dbow_dmm = get_concat_vectors(model_dbow,model_dmm,x_train,200)
val_vecs_dbow_dmm = get_concat_vectors(model_dbow,model_dmm,x_val,200)train_vecs_dbow_dmc = get_concat_vectors(model_dbow,model_dmc,x_train,200)
val_vecs_dbow_dmc = get_concat_vectors(model_dbow,model_dmc,x_val,200)

现在,我们使用相同的 sklearn 算法,以类似的方式使用这五个向量进行分类(就像我们对 CV 和 Tfidf 所做的那样)。

vecs = [(train_vecs_dbow,val_vecs_dbow),(train_vecs_dmc,val_vecs_dmc),(train_vecs_dmm,val_vecs_dmm),(train_vecs_dbow_dmm,val_vecs_dbow_dmm),(train_vecs_dbow_dmc,val_vecs_dbow_dmc)]
classifiers = [BernoulliNB(),LogisticRegression(),LinearSVC(),AdaBoostClassifier(),RidgeClassifier(),PassiveAggressiveClassifier(),Perceptron()]
gensim_names = ['DBOW','DMC','DMM','DBOW+DMM','DBOW+DMC']
data=[]
for train_vecs,val_vecs in vecs:
    for clf in classifiers:
        clf.fit(train_vecs,y_train)
        ac = clf.score(val_vecs,y_val)
        data.append([gensim_names[j],clf_names[i],ac,end-start])
d = pd.DataFrame(data,columns=['Model','Classifier','Ac','Time'])
d.to_csv('gensim_all_clfs.csv')

上面只给出了几行重要的代码。参见

让我们看看结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Results using Gensim models

逻辑回归(DBOW)、线性 SVC(DBOW)、逻辑回归(DBOW +DMC)和线性 SVC(DBOW+DMC)给出了 65.35%的最高准确度。考虑到训练时间,逻辑回归(DBOW)是其中最好的一个(0.52 秒)。RidgeClassifier(DBOW)也表现出良好的性能,准确率为 64.2%,训练时间仅为 0.007 秒。DBOW 模型优于其他两个模型,平均准确率(在所有分类器中)为 60.4%。Gensim 模型的性能比 CV 和 Tfidf 模型稍差。

总之,被动主动分类器(Tfidf-bigrams)的性能最好,准确率为 83.57%。所以我们用测试数据来评估一下。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import PassiveAggressiveClassifier
from sklearn.pipeline import make_pipeline
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score,precision_score,recall_score
import time
b=2
st = time.time()
tfidf = TfidfVectorizer(ngram_range=(1,b))
model = make_pipeline(tfidf,PassiveAggressiveClassifier())
model.fit(x_train.values.astype('U'),y_train.values.astype('U'))##
labels = model.predict(x_test.values.astype('U'))###cm = confusion_matrix(y_test.values.astype('U'),labels)
ac = accuracy_score(y_test.values.astype('U'),labels)
pr = precision_score(y_test.values.astype('U'),labels,average=None)
rc = recall_score(y_test.values.astype('U'),labels,average=None)
en = time.time()
print(b,"-gram",ac,pr.mean(),rc.mean(),en-st)

当在测试数据上评估该模型时,它给出了 80.42%的准确度。

摘要

使用 Tweepy 库收集推文,然后选择对我的任务有用的功能并转换为 CSV。然后,执行数据清理,如删除 URL、转发符号、用户名标签和标签。SentiWordNet 词典用于标注推文的情绪。对文本数据执行诸如停用词移除、词汇化、词干化之类的步骤。后来用 WordCloud 做数据可视化。拆分数据后,Count 矢量器和 Tfidf 矢量器用于文本的数学表示。然后,对先前获得的向量实施九种分类算法。后来,doc2vec 模型(DBOW、DMC、DMM)被训练并使用向量(通过这些模型获得)用于分类目的,因为这些模型保留了单词之间的语义关系。最后,使用测试数据评估最佳模型。

欢迎对这个项目的改进提出任何建议。感谢您的阅读!

参考文献

1https://towards data science . com/another-Twitter-opinion-analysis-with-python-part-6-doc 2 vec-603 f 11832504

2https://bhaskarvk . github . io/2015/01/how-to-use-twitters-search-rest-API-most-effectively。/

3https://medium . com/analytics-vid hya/Twitter-opinion-analysis-for-the-2019-election-8f 7d 52 af 1887

4 https://chrisalbon . com/machine _ learning/trees _ and _ forests/handle _ unbalanced _ classes _ in _ random _ forests/

情感分析:简化

原文:https://towardsdatascience.com/sentiment-analysis-simplified-ac30720a5827?source=collection_archive---------19-----------------------

看看自然语言处理的“你好世界”

什么是情感分析?

情感分析是自然语言处理的一个领域,负责从自然语言中提取观点的系统。NLP 的目标是创建能够像我们人类一样理解语言的管道。情感分析是自然语言处理中最基本的问题之一,也是学生在自然语言处理课程中首先面临的问题之一。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为什么要进行情感分析?

从能够从产品评论中挖掘意见到能够通过研究推文来预测股票价格,情绪分析有非常广泛的应用。由于问题的直观性,情感分析构成了我们称之为自然语言理解的几乎所有其他管道的基础。

从讲师的角度来看,情感分析包含了在 NLP 工作的数据科学家应该了解的一切。句子处理和 NLP 中使用的所有通用模型/架构都可以包含在情感分析的范围内。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

情感分析的类型

情感分析本质上是一个分类问题。虽然情感分析包含各种各样的问题,但最常见的类型可以大致分为:

  1. 极性检测:谈论句子的极性,即正、负或中性。有时,分类甚至可以更精细,如非常积极、积极、中性、消极和非常消极。
  2. 情感检测:从句子中检测说话者的情感,例如,高兴、悲伤、生气等。
  3. 意图检测:不仅能够检测出句子中的内容,还能检测出句子的意图。

基本管道

让我们首先讨论从原始文本中提取特征。提供给情感分析的输入并不都是有用的。虽然最近的深度学习模型已经促进了将所有特征工程转移到这些模型,但是 NLP 实践者仍然更喜欢在通过任何管道之前清理输入。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在将单词转换成数学特征后,情感分析就变得类似于一个时间序列问题。这是因为在一个句子中使用的单词彼此相关,它们在句子中出现的顺序也很重要。最近,基于 LSTM 的深度学习模型在情感分析方面非常成功。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下一步是什么?

情感分析的最大挑战之一是能够捕捉句子出现的上下文及其语气。讽刺是普通情感分析系统面临的最大问题之一。研究人员目前正在努力提高理解上下文的能力。

这个博客是努力创建机器学习领域简化介绍的一部分。点击此处查看完整系列

[## 机器学习:简化

在你一头扎进去之前就知道了

towardsdatascience.com](/machine-learning-simplified-1fe22fec0fac)

或者只是阅读系列的下一篇博客

[## 社交网络中有影响力的社区:简化版

为什么要研究社交网络中的社区?社交网络是大规模现实世界网络的主要例子。他们…

towardsdatascience.com](/influential-communities-in-social-network-simplified-fe5050dbe5a4)

参考文献

【1】https://monkey learn . com/情操-分析/#情操-分析-用例-应用 【2】刘、冰。"情感分析和观点挖掘.“人类语言技术综合讲座 5.1(2012):1–167。
[3]帕克、亚历山大、帕特里克·帕鲁贝克。” Twitter 作为情感分析和观点挖掘的语料库."LREc。第十卷。№2010.2010.
[4]王、叶泉、黄敏烈、李昭。"面向方面级情感分类的基于注意力的 LSTM . "2016 年自然语言处理经验方法会议论文集。2016.

使用 ALBERT 进行情感分析

原文:https://towardsdatascience.com/sentiment-analysis-using-albert-938eb9029744?source=collection_archive---------14-----------------------

使用 Albert 进行情感分析

让我们微调谷歌最新的情感分析任务的自然语言处理模型

每个研究人员或 NLP 从业者都很清楚 2018 年到来的 BERT。从那时起,NLP 行业已经发生了很大的变化。

阿尔伯特是一个 Lite 伯特是在焦点,使它尽可能轻,通过减少参数大小。

深度学习对于情感分析任务的巨大优势是我们预处理数据的步骤减少了。唯一需要的预处理是将它们转换成小写字母。如果我们使用机器学习方法,如 TF-IDF 的逻辑回归,那么你需要将单词词条化,并删除不必要的单词。如果你正在考虑删除停用词,那么看看这篇文章

[## 为什么应该避免删除停用词

删除停用词真的能提高模型性能吗?

towardsdatascience.com](/why-you-should-avoid-removing-stopwords-aa7a353d2a52)

如果您想了解最新的文本预处理步骤,请查阅这篇文章。

[## 面向情感分析的文本预处理技术

让我们讨论一些技术的缺点以及如何改进它们

towardsdatascience.com](/updated-text-preprocessing-techniques-for-sentiment-analysis-549af7fe412a) 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Headway on Unsplash

微调

  1. 首先克隆这个 GitHub repo
  2. 准备数据集。制表符分隔的(。tsv)文件是必需的。数据集需要放在同一目录的文件夹中。
  3. 数据集将有 2 列。一个包含文本,另一个包含标签。
  4. 写入列车命令
$ python run_glue.py --data_dir data --model_type albert --model_name_or_path albert-base-v2 --output_dir output --do_train --task_type sst-2

命令行参数-

数据目录 -存放 train.tsv 文件的地方

model_type -您想要用于情感分析任务的模型。这里我们用的是阿尔伯特

model _ name _ or _ path-您要使用的模型的变体。这里我们使用的是 albert-base-v2。

输出-目录- 你想要保存模型的目录。该脚本将自动创建文件夹。

do-train - 因为我们正在进行列车运行。

task_type - 可以执行两个任务——SST-2 和 SST-5。

以下是您可以使用的各种型号的列表

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

source

5.在模型被训练之后,所有的模型文件都将在一个文件夹中。

6.替换 api.py 文件中的模型目录。

7.运行 api.py 文件

$ python api.py

8.如果你想调用它的预测方法

$ from api import SentimentAnalyzer
$ classifier = SentimentAnalyszer()
$ classifier.predict('It was a good movie')

参考

  1. https://github . com/Google-research/Google-research/tree/master/Albert
  2. https://github.com/huggingface/transformers

使用 LSTM 进行情感分析(循序渐进教程)

原文:https://towardsdatascience.com/sentiment-analysis-using-lstm-step-by-step-50d074f09948?source=collection_archive---------0-----------------------

使用 PyTorch 框架进行深度学习

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sentiment Analysis, Image by: Monkeylearn

什么是情绪分析:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sentiment Analysis from Dictionary

我认为谷歌词典的这个结果给出了一个非常简洁的定义。我不用再强调情感分析变得多么重要了。因此,这里我们将在 IMDB 电影数据集上建立一个分类器,使用一种叫做 RNN 的深度学习技术。

我概述了如何使用长短期记忆(LSTM) 架构实现递归神经网络(RNN) 的逐步过程:

  1. 加载并可视化数据
  2. 数据处理—转换为小写
  3. 数据处理—删除标点符号
  4. 数据处理—创建评论列表
  5. Tokenize 创建 Vocab 到 Int 映射字典
  6. 标记化—对单词进行编码
  7. 标记化—对标签进行编码
  8. 分析评论长度
  9. 去除离群值——去除过长或过短的评论
  10. 填充/截断剩余数据
  11. 训练、验证、测试数据集分割
  12. 数据加载器和批处理
  13. 定义 LSTM 网络架构
  14. 定义模型类
  15. 训练网络
  16. 测试(针对测试数据和用户生成的数据)

1 )载入并可视化数据

我们正在使用 IMDB 电影评论数据集。如果它以 txt 文件的形式存储在你的机器中,那么我们只需把它加载进来

**# read data from text files**
with open(‘data/reviews.txt’, ‘r’) as f:
 reviews = f.read()
with open(‘data/labels.txt’, ‘r’) as f:
 labels = f.read()print(reviews[:50])
print()
print(labels[:26])**--- Output ---**bromwell high is a cartoon comedy . it ran at the same time as some other programs about school life  such as  teachers  . my   yearspositive
negative
positive

2 )数据处理—转换成小写

reviews = reviews.lower()

3 数据处理—去掉标点符号

from string import punctuation
print(punctuation)**--- Output ---**!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

我们看到了 python 中预定义的所有标点符号。为了去掉所有这些标点符号,我们将简单地使用

all_text = ''.join([c for c in reviews if c not in punctuation])

4)数据处理—创建评论列表

我们把所有的字符串都放在一个大字符串中。现在,我们将分离出单独的评论,并将它们存储为单独的列表元素。像【点评 _1,点评 _2,点评 _3……】。复习 _n]

reviews_split = all_text.split(‘\n’)
print ('Number of reviews :', len(reviews_split))

评论数量:25001

5)标记化—创建 Vocab 到 Int 的映射字典

在大多数 NLP 任务中,您将创建一个索引映射字典,以便为经常出现的单词分配较低的索引。最常见的方法之一是使用Collections库中的Counter方法。

from collections import Counterall_text2 = ' '.join(reviews_split)
# create a list of words
words = all_text2.split()# Count all the words using Counter Method
count_words = Counter(words)

total_words = len(words)
sorted_words = count_words.most_common(total_words)

让我们来看看我们创建的这些对象

print (count_words)**--- Output ---**Counter({'the': 336713, 'and': 164107, 'a': 163009, 'of': 145864

为了创建一个 vocab 到 int 的映射字典,您只需这样做

vocab_to_int = {w:i for i, (w,c) in enumerate(sorted_words)}

这里有一个小技巧,在这个映射中,索引将从 0 开始,即“the”的映射将是 0。但是稍后我们将为较短的评论填充,填充的常规选择是 0。所以我们需要从 1 开始索引

vocab_to_int = {w:i+1 for i, (w,c) in enumerate(sorted_words)}

让我们来看看这个映射字典。我们可以看到“the”的映射现在是 1

print (vocab_to_int)**--- Output ---**{'the': 1, 'and': 2, 'a': 3, 'of': 4,

6)标记化——对单词进行编码

到目前为止,我们已经使用来自所有评论的 vocab 创建了 a)评论列表和 b)索引映射字典。所有这些都是为了创建评论的编码(用整数代替评论中的单词)

reviews_int = []
for review in reviews_split:
    r = [vocab_to_int[w] for w in review.split()]
    reviews_int.append(r)
print (reviews_int[0:3])**--- Output ---**[[21025, 308, 6, 3, 1050, 207, 8, 2138, 32, 1, 171, 57, 15, 49, 81, 5785, 44, 382, 110, 140, 15, .....], [5194, 60, 154, 9, 1, 4975, 5852, 475, 71, 5, 260, 12, 21025, 308, 13, 1978, 6, 74, 2395, 5, 613, 73, 6, 5194, 1, 24103, 5, ....], [1983, 10166, 1, 5786, 1499, 36, 51, 66, 204, 145, 67, 1199, 5194.....]]

注意:我们现在创建的是一个列表列表。每个评论都是一个整数值列表,所有这些都存储在一个巨大的列表中

7)标记化——对标签进行编码

这很简单,因为我们只有 2 个输出标签。因此,我们将“正”标记为 1,“负”标记为 0

encoded_labels = [1 if label =='positive' else 0 for label in labels_split]
encoded_labels = np.array(encoded_labels)

8)分析评论长度

import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inlinereviews_len = [len(x) for x in reviews_int]
pd.Series(reviews_len).hist()
plt.show()pd.Series(reviews_len).describe()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Review Length Analysis

观察结果 : a)平均评论长度= 240 b)部分评论长度为 0。保留此评论对我们的分析没有任何意义 c)大多数评论少于 500 字或更多 d)有相当多的评论非常长,我们可以手动调查它们,以检查我们是否需要将它们包括在我们的分析中或从我们的分析中排除

9)剔除异常值——剔除过长或过短的评论

reviews_int = [ reviews_int[i] for i, l in enumerate(reviews_len) if l>0 ]
encoded_labels = [ encoded_labels[i] for i, l in enumerate(reviews_len) if l> 0 ]

10)填充/截断剩余数据

为了处理短评论和长评论,我们会将所有评论填充或截断到特定长度。我们用**序列长度来定义这个长度。**该序列长度与 LSTM 层的时间步数相同。

对于比seq_length短的评论,我们会用 0 填充。对于长于seq_length的评论,我们会将其截断为第一个 seq_length 单词。

def pad_features(reviews_int, seq_length):
    ''' Return features of review_ints, where each review is padded with 0's or truncated to the input seq_length.
    '''
    features = np.zeros((len(reviews_int), seq_length), dtype = int)

    for i, review in enumerate(reviews_int):
        review_len = len(review)

        if review_len <= seq_length:
            zeroes = list(np.zeros(seq_length-review_len))
            new = zeroes+review elif review_len > seq_length:
            new = review[0:seq_length]

        features[i,:] = np.array(new)

    return features

注意:我们正在创建/维护一个 2D 数组结构,就像我们为reviews_int创建的一样。输出将如下所示

print (features[:10,:])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

11)训练、验证、测试数据集拆分

一旦我们把数据整理好,我们将把它分成训练集、验证集和测试集

训练= 80% |有效= 10% |测试= 10%

split_frac = 0.8
train_x = features[0:int(split_frac*len_feat)]
train_y = encoded_labels[0:int(split_frac*len_feat)]remaining_x = features[int(split_frac*len_feat):]
remaining_y = encoded_labels[int(split_frac*len_feat):]valid_x = remaining_x[0:int(len(remaining_x)*0.5)]
valid_y = remaining_y[0:int(len(remaining_y)*0.5)]test_x = remaining_x[int(len(remaining_x)*0.5):]
test_y = remaining_y[int(len(remaining_y)*0.5):]

12)数据加载器和批处理

在创建我们的训练、测试和验证数据之后。下一步是为这些数据创建数据加载器。我们可以使用生成器函数将我们的数据分批,而不是使用 TensorDataset 。这是 PyTorch 中一个非常有用的实用程序,可以像使用 torchvision 数据集一样轻松地使用数据加载器的数据

import torch
from torch.utils.data import DataLoader, TensorDataset# create Tensor datasets
train_data = TensorDataset(torch.from_numpy(train_x), torch.from_numpy(train_y))
valid_data = TensorDataset(torch.from_numpy(valid_x), torch.from_numpy(valid_y))
test_data = TensorDataset(torch.from_numpy(test_x), torch.from_numpy(test_y))# dataloaders
batch_size = 50# make sure to SHUFFLE your data
train_loader = DataLoader(train_data, shuffle=True, batch_size=batch_size)
valid_loader = DataLoader(valid_data, shuffle=True, batch_size=batch_size)
test_loader = DataLoader(test_data, shuffle=True, batch_size=batch_size)

为了获得一批可视化的训练数据,我们将创建一个数据迭代器

# obtain one batch of training data
dataiter = iter(train_loader)
sample_x, sample_y = dataiter.next()print('Sample input size: ', sample_x.size()) # batch_size, seq_length
print('Sample input: \n', sample_x)
print()
print('Sample label size: ', sample_y.size()) # batch_size
print('Sample label: \n', sample_y)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里,50 是批量大小,200 是我们定义的序列长度。现在,我们的数据准备步骤已经完成,接下来我们将查看 LSTM 网络架构,以开始构建我们的模型

13 )定义 LSTM 网络架构

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

LSTM Architecture for Sentiment Analysis. Image by Author

这些层如下所示:

0.令牌化:这不是 LSTM 网络的一个层,而是将我们的单词转换成令牌(整数)的一个强制步骤

  1. 嵌入层:将单词标记(整数)转换成特定大小的嵌入
  2. LSTM 层:由隐藏状态变暗和层数定义
  3. 全连接图层:将 LSTM 图层的输出映射到所需的输出大小
  4. Sigmoid 激活层:将所有输出值转换为 0 到 1 之间的值
  5. 输出:最后一个时间步长的 Sigmoid 输出被认为是该网络的最终输出

注:如果你想更多地了解这些 LSTM 层,并获得事物的微观观点。读读这个—

[## 层间阅读(LSTM 网络)

使用 PyTorch 框架进行深度学习

towardsdatascience.com](/reading-between-the-layers-lstm-network-7956ad192e58)

14)定义模型类

15)训练网络

  • 实例化网络
# Instantiate the model w/ hyperparams
vocab_size = len(vocab_to_int)+1 # +1 for the 0 padding
output_size = 1
embedding_dim = 400
hidden_dim = 256
n_layers = 2net = SentimentLSTM(vocab_size, output_size, embedding_dim, hidden_dim, n_layers)print(net)SentimentLSTM(
  (embedding): Embedding(74073, 400)
  (lstm): LSTM(400, 256, num_layers=2, batch_first=True, dropout=0.5)
  (dropout): Dropout(p=0.3)
  (fc): Linear(in_features=256, out_features=1, bias=True)
  (sig): Sigmoid()
)
  • 训练循环

training loop 中的大多数代码都是非常标准的深度学习训练代码,您可能会在所有使用 PyTorch 框架的实现中经常看到这些代码。

16)测试

  • 关于测试数据

  • 关于用户生成的数据

首先,我们将定义一个负责预处理步骤的tokenize函数,然后我们将创建一个predict函数,它将在解析用户提供的评论后给出最终输出。

结果:

test_review = 'This movie had the best acting and the dialogue was so good. I loved it.'seq_length=200 # good to use the length that was trained onpredict(net, test_review_neg, seq_length)

阳性审查检出

感谢阅读!

  • 如果你喜欢这个,关注我的 medium 了解更多。
  • 你们的掌声对写更多、写得更好是一个巨大的鼓励和帮助。
  • 有兴趣合作吗?我们在 Linkedin 上连线吧。
  • 请随意写下您的想法/建议/反馈。

更新:另一篇文章给你一个在层内发生的事情的微观视角。

[## 层间阅读(LSTM 网络)

使用 PyTorch 框架进行深度学习

towardsdatascience.com](/reading-between-the-layers-lstm-network-7956ad192e58)

基于深度学习的网飞评论情感分析

原文:https://towardsdatascience.com/sentiment-analysis-with-deep-learning-62d4d0166ef6?source=collection_archive---------5-----------------------

深入分析

网飞评论中人类情感的识别和分类

在这篇文章中,我将涉及情感分析的主题,以及如何实现一个深度学习模型,该模型可以识别和分类网飞评论中的人类情感。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你喜欢这篇文章,想分享你的想法,问问题或保持联系,请随时通过 LinkedIn 与我联系。

对企业来说,最重要的因素之一是与客户群保持联系。对于这些公司来说,准确地了解消费者或客户对新的和现有的产品或服务、最近的计划和客户服务的想法是至关重要的。

情感分析是完成这一必要任务的一种方式。

情感分析是自然语言处理(NLP)的一个领域,它建立模型,试图识别和分类表达的属性,例如:

  • 极性:如果说话人表达了正面负面的意见,
  • 主题:正在谈论的事情,
  • 意见持有人:表达意见的个人或实体。

在我们每天产生 2.5 万亿字节数据的世界里,情感分析已经成为理解这些数据的关键工具。这使得公司能够获得关键的洞察力,并自动化各种流程。

情感分析可以帮助将非结构化信息自动转换为公众对产品、服务、品牌、政治或人们可以表达意见的任何其他主题的意见的结构化数据。这些数据对于商业应用非常有用,如市场分析公共关系产品评论网络推广评分产品反馈和客户服务

在下文中,我将向您展示如何实现一个深度学习模型,该模型可以将网飞的评论分为正面或负面。该模型将整个评论作为输入(一个词接一个词),并提供百分比评级,以检查评论是否传达了积极或消极的情绪。

我使用的数据集包含大约 5000 个负面和 5000 个正面评论。这里是来自数据集的 5 个样本评论,在文章的最后将按照模型进行分类:

 ***"The film is a hoot and is just as good if not better than much of what s on saturday morning tv, especially the pseudo educational stuff we all can’t stand.” 

"The things this movie tries to get the audience to buy just won’t fly with most intelligent viewers.”******"Although life or something like it is very much in the mold of feel good movies, the cast and director stephen herek’s polished direction pour delightfully piquant wine from aged bottles.”

"This is the case of a pregnant premise being wasted by a script that takes few chances and manages to insult the intelligence of everyone in the audience.”

"One of the finest most humane and important holocaust movies ever made."***

深度学习模型+所有必要的数据可以在我的 GitHub repo 中找到。

让我们从一些理论开始。

1.递归神经网络

递归神经网络 ( RNNs )是流行的模型,在许多 NLP 任务中显示出巨大的前景。

RNN 的利用文本等顺序信息。在“传统的”前馈神经网络中,我们假设所有的输入都是相互独立的。但是对于许多任务来说,这是一个非常糟糕的想法。例如,一个句子具有清晰的语法结构和顺序,其中每个单词都依赖于前一个单词。如果你想让你的神经网络学习意思(或者在我们的例子中是情感),网络必须知道哪些单词以什么顺序出现。

rnn被称为递归,因为它们对序列的每个元素执行相同的任务,其输出取决于之前的计算。另一种看待 rnn 的方式是,它们有一个“记忆”,这个“记忆”记录了到目前为止已经计算过的信息。这是一个典型的 RNN 的样子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Fig. 1 Recurrent Neural Network architecture.

【x(t-1)x(t)x(t+1) 是相互依赖的顺序输入(如句子中的词)。***【y(t _ 1)y(t)y(t+1)都是输出。对 RNN 来说独一无二的是,计算当前隐藏状态【t】的神经元对于输入的【t】依赖于先前的隐藏状态【t-1】对于先前的输入【t-1】WxhWhh 是连接输入【x(t)与隐藏层【t】,以及 h(t)【t-1】***的权重矩阵这样,我们向神经网络引入了一个递归,该递归可以被认为是对先前输入的记忆。理论上,这种方式“香草” RNNs 可以利用任意长序列中的信息,但在实践中,它们被限制为只能回顾几步。

这就是 LSTMs 派上用场的地方。

1.1 个 LSTMs

长短期记忆网络——通常简称为“lstm”——是一种特殊的 RNN ,能够学习长期依赖关系。lstm 的架构与rnn没有本质上的不同,但是它们集成了额外的组件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

LSTMs 的关键是单元格状态***【C(t),贯穿图表顶部的水平线。单元状态是除了仅使用隐藏状态【t】***之外的另一种存储内存的方式。然而, C(t) 使得 LSTMs 可以与普通 RNNs 相反地处理更长的序列。

此外,LSTMs 有能力删除或添加信息到细胞状态,由称为门的结构仔细调节。门是选择性地让信息通过的一种方式。一个 LSTM 有三个这样的门,用来保护和控制细胞状态。

  • 遗忘门:在得到隐藏状态 h(t-1 ) of 之前的输入 x(t-1) 之后,遗忘门帮助我们决定什么必须从***【t-1】***状态中删除,从而只保留相关的东西。
  • 输入门:在输入门中,我们决定将当前输入的新东西添加到我们当前的单元格状态【C(t)
  • **输出门:输出门顾名思义,决定从当前单元状态【C(t)到下一个【C(t+1)**输出什么。对于语言模型示例,由于它刚刚看到了一个主题,它可能希望输出与一个动词相关的信息,以防接下来会出现这个信息。例如,它可能会输出主语是单数还是复数,这样我们就知道动词应该变成什么形式,如果接下来是什么形式的话。

每种状态背后都有独立的神经网络。可以想象,这使得 LSTMs 非常复杂。在这一点上,我不会去更多的关于 LSTMs 的细节。

2.预处理

在我们可以使用评论作为递归神经网络的输入之前,需要对数据进行一些预处理。我们在这里的主要目的是缩小观察空间。

2.1 单词的统一拼写

考虑一下“ 有事 ”和“ 有事 ”这样的词。对于我们人类来说,这些单词有着相同的意思,它们之间唯一的区别是第一个单词是大写的,因为它可能是一个句子中的第一个单词。但是对于神经网络来说,这些单词将会有(至少在开始时)不同的意思,因为它们的拼写不同。只有在训练期间,神经网络可能会也可能不会学会识别这些单词的意思。我们的目标是防止这种误解。

正因为如此,预处理的第一步就是把所有的单词都变成小写的单词。

2.2 删除特殊字符

特殊字符如*。,** **?*等。不会影响评论的情绪,因此可以删除。

最终结果

考虑以下未处理的审查样本:

****"Although life or something like it is very much in the mold of feel good movies, the cast and director stephen herek’s polished direction pour delightfully piquant wine from aged bottles.”****

在我们完成前面提到的预处理步骤后,review 示例如下所示:

****"although life or something like it is very much in the mold of feel good movies the cast and director stephen hereks polished direction pour delightfully piquant wine from aged bottles”****

预处理应用于数据集中的每个评论。

2.3 词对索引

另一个主要步骤是创建所谓的单词到索引映射*,它为数据集中的每个单词分配一个唯一的整数值。我在这个项目中使用的包含所有正面和负面评论的数据集由 18339 个独特的单词组成。因此,单词-索引映射具有相同数量的条目。这个数字也被称为词汇量。*

我获得的单词到索引映射中的第一个和最后一个条目如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为数据集中的单词分配唯一整数的这一步至关重要,因为我们不能将字符串数据输入到神经网络中。相反,word-to-index 允许我们使用整数来表示整个句子和评论。考虑下面的评论:

****"the things this movie tries to get the audience to buy just wont fly with most intelligent viewers”****

使用单词到索引的映射,评论可以由整数数组表示,其中每个整数根据映射表示一个单词:

****[0, 5094, 147, 81, 1269, 5, 532, 0, 1303, 5, 1835, 652, 236, 1101, 125, 188, 712, 855]****

3.单词嵌入

当然,神经网络既不能接受字符串,也不能接受单个整数值作为输入。相反,我们必须使用单词嵌入*。*

**单词嵌入是文本的分布式表示,这可能是深度学习方法在挑战 NLP 问题上令人印象深刻的表现的关键突破之一。单词嵌入实际上是一类技术,其中单个单词由一个实值向量表示,通常有几十或几百维。每个单词被映射到一个特定的向量,向量值由神经网络学习。

这与稀疏单词表示所需的数千或数百万维形成对比,例如一键编码。例如,我们可以嵌入单词 “虽然”“生活” 作为 10 维向量:

****although = [0.8 1.0 4.2 7.5 3.6]
life = [8.3 5.7 7.8 4.6 2.5 ]****

代表数据集中一个单词的每个向量都是从一个称为嵌入矩阵的大矩阵中获得的。该矩阵的行数表示单词嵌入的维度,列数表示词汇大小或数据集中唯一单词的数量。因此,该矩阵的每一列代表数据集中唯一单词的嵌入向量。

我们怎么知道哪一列代表哪个单词?这就是我们使用单词到索引映射的地方。考虑你想要得到单词 【虽然】, 的嵌入向量,根据单词到索引的映射,这个单词由数字 2511 表示。在下一步中,需要创建一个大小为 18339 ( 数据集中的字数),的单热编码向量,其中除了值为 1 的第 2511 个条目之外,每个条目都为 0。

通过在嵌入矩阵和一位热编码向量之间做点积,我们获得矩阵的第 2511 列,这是单词 “虽然”的嵌入向量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这样,我们可以将整个字符串或网飞评论输入到 LSTM 中。我们只需在单词到索引的映射中查找每个单词的整数值,创建适当的一个热编码向量,并用矩阵执行点积。这篇评论然后被一个字一个字地(一个向量接一个向量地)输入 LSTM 的网络。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.获取评论的情绪

到目前为止,您已经看到了如何预处理数据以及如何在 LSTM 网络中输入评论。现在,让我们讨论如何最终获得给定评论的情感。

*对于每个时间步长 t ,LSTM 网络接收输入向量 x(t) ,这产生输出向量 y(t) 。重复该过程,直到 x(n),n 是评论中的字数。就说 n =20 个字吧。直到**x(n)*LSTM网络产生了 y(n) 输出向量。这 20 个向量中的每一个都代表了一些东西,但不是我们要寻找的情感。更确切地说,向量 y 是评论特征的编码表示,其(根据神经网络)在确定情感方面将是重要的。

y(8) 代表神经网络为评论的前 8 个单词识别的特征。另一方面, y(20) 代表整个评论的特征。尽管在实践中仅使用最后的输出向量 y(20) 就足够了,但是我已经发现,如果我们使用所有的向量 y(0) — y(20) 来确定情感,则会导致更准确的结果。这可以通过计算所有向量的平均值来实现。我们姑且称这个均值向量 y_mean。

最后,在 y_mean 中编码的评论的特征表示可用于将评论分类为正面或负面的类别。为了做到这一点,需要添加一个最终的分类层,它无非是 y_mean 和另一个权重矩阵 W 之间的点积。

我刚才描述的这个情感分析的过程是在我的GitHub repo中的一个深度学习模型中实现的。欢迎大家来看看,亲自尝试一下。在模型被训练之后,可以对尚未看到的评论执行情感分析:

***Test Samples:****Review**: "the film is a hoot and is just as good if not better than   much of whats on saturday morning tv especially the pseudo educational stuff we all cant stand"**pos. sentiment:** 0.96 %
**neg. sentiment:** 0.04 % **Review:** "the things this movie tries to get the audience to buy just wont fly with most intelligent viewers"**pos. sentiment:** 0.11 % **neg. sentiment:** 0.89 % **Review:** "although life or something like it is very much in the mold of feel good movies the cast and director stephen hereks polished direction pour delightfully piquant wine from aged bottles"**pos. sentiment:** 0.97 %
**neg. sentiment:** 0.03 % **Review:** "this is the case of a pregnant premise being wasted by a script that takes few chances and manages to insult the intelligence of everyone in the audience"**pos. sentiment:** 0.02 %
**neg. sentiment:** 0.98 %*

用 Python 进行情感分析(第 2 部分)

原文:https://towardsdatascience.com/sentiment-analysis-with-python-part-2-4f71e7bde59a?source=collection_archive---------4-----------------------

改进电影评论情感分类器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by izayah ramos on Unsplash

在这个系列的第一部分,我们建立了一个准系统的电影评论情感分类器。下一篇文章的目标是概述几种可以用来增强 NLP 模型的技术。也就是说,我们不会在任何特定的话题上做太深入的探讨。

如果你还没有,你可以在这里阅读我的第一篇文章:

[## 用 Python 进行情感分析(第 1 部分)

IMDb 电影评论分类

towardsdatascience.com](/sentiment-analysis-with-python-part-1-5ce197074184)

本系列中使用的所有代码以及补充材料都可以在这个 GitHub 资源库中找到。

文本处理

对于我们的第一次迭代,我们做了非常基本的文本处理,如删除标点符号和 HTML 标签,并使一切都小写。我们可以通过删除停用词和规范文本来进一步清理。

为了进行这些转换,我们将使用自然语言工具包 (NLTK)中的库。这是一个非常流行的 Python 的 NLP 库。

删除停用词

停用词是非常常见的词,如“如果”、“但是”、“我们”、“他”、“她”和“他们”。我们通常可以在不改变文本语义的情况下删除这些单词,并且经常(但不总是)这样做可以提高模型的性能。当我们开始使用更长的单词序列作为模型特征时,删除这些停用词变得更加有用(见下面的 n-grams)。

之前

"bromwell high is a cartoon comedy it ran at the same time as some other programs about school life such as teachers my years in the teaching profession lead me to believe that bromwell high’s satire is much closer to reality than is teachers the scramble to survive financially the insightful students who can see right through their pathetic teachers’ pomp the pettiness of the whole situation all remind me of the schools i knew and their students when i saw the episode in which a student repeatedly tried to burn down the school i immediately recalled at high a classic line inspector i’m here to sack one of your teachers student welcome to bromwell high i expect that many adults of my age think that bromwell high is far fetched what a pity that it isn’t"

之后

"bromwell high cartoon comedy ran time programs school life teachers years teaching profession lead believe bromwell high's satire much closer reality teachers scramble survive financially insightful students see right pathetic teachers' pomp pettiness whole situation remind schools knew students saw episode student repeatedly tried burn school immediately recalled high classic line inspector i'm sack one teachers student welcome bromwell high expect many adults age think bromwell high far fetched pity"

**注意:**在实践中,删除停用词的一个更简单的方法是在 scikit-learn 的任何“矢量器”类中使用stop_words参数。如果你想使用 NLTK 的停用词完整列表,你可以做stop_words='english’。在实践中,我发现使用 NLTK 的列表实际上会降低我的性能,因为它太昂贵了,所以我通常提供我自己的单词列表。例如,stop_words=['in','of','at','a','the']

正常化

文本预处理的一个常见的下一步是通过将一个给定单词的所有不同形式转换成一个来使你的语料库中的单词规范化。存在的两种方法是词干词汇化

词干

词干被认为是更原始/更强力的规范化方法(尽管这不一定意味着它的性能会更差)。有几种算法,但总的来说,它们都使用基本规则来切断单词的结尾。

NLTK 有几个词干算法实现。我们将在这里使用波特词干分析器,但是你可以在这里通过例子探索所有的选项: NLTK 词干分析器

词汇化

词汇化的工作原理是识别给定单词的词性,然后应用更复杂的规则将该单词转换为其真正的词根。

结果

没有归一化

"this is not the typical mel brooks film it was much less slapstick than most of his movies and actually had a plot that was followable leslie ann warren made the movie she is such a fantastic under rated actress there were some moments that could have been fleshed out a bit more and some scenes that could probably have been cut to make the room to do so but all in all this is worth the price to rent and see it the acting was good overall brooks himself did a good job without his characteristic speaking to directly to the audience again warren was the best actor in the movie but fume and sailor both played their parts well"

词干

"thi is not the typic mel brook film it wa much less slapstick than most of hi movi and actual had a plot that wa follow lesli ann warren made the movi she is such a fantast under rate actress there were some moment that could have been flesh out a bit more and some scene that could probabl have been cut to make the room to do so but all in all thi is worth the price to rent and see it the act wa good overal brook himself did a good job without hi characterist speak to directli to the audienc again warren wa the best actor in the movi but fume and sailor both play their part well"

术语化

"this is not the typical mel brook film it wa much le slapstick than most of his movie and actually had a plot that wa followable leslie ann warren made the movie she is such a fantastic under rated actress there were some moment that could have been fleshed out a bit more and some scene that could probably have been cut to make the room to do so but all in all this is worth the price to rent and see it the acting wa good overall brook himself did a good job without his characteristic speaking to directly to the audience again warren wa the best actor in the movie but fume and sailor both played their part well"

n-grams

上次我们在模型中只使用了单个单词的特征,我们称之为 1-grams 或 unigrams。我们还可以通过添加两个或三个单词序列(二元模型或三元模型)来为我们的模型增加更多的预测能力。例如,如果一条评论有三个单词序列“不喜欢电影”,我们只会用单字母模型单独考虑这些单词,可能不会捕捉到这实际上是一种负面的情绪,因为单词“喜欢”本身将与正面评论高度相关。

scikit-learn 库使这变得非常容易。只需对任何“矢量器”类使用ngram_range参数。

接近 90%了!因此,除了单个单词之外,简单地考虑两个单词的序列将我们的准确率提高了 1.6 个百分点以上。

注意:对于你的模型,n 的大小在技术上没有限制,但是有几件事需要考虑。第一,增加克数不一定会给你更好的表现。其次,随着 n 的增加,矩阵的大小呈指数增长,因此,如果您有一个由大型文档组成的大型语料库,您的模型可能需要很长时间来训练。

陈述

在第 1 部分中,我们将每个评论表示为一个二元向量(1 和 0 ),语料库中的每个唯一单词都有一个槽/列,其中 1 表示给定的单词在评论中。

虽然这种简单的方法可以很好地工作,但我们有办法将更多的信息编码到向量中。

字数

我们可以包括给定单词出现的次数,而不是简单地记录一个单词是否出现在评论中。这可以给我们的情感分类器更多的预测能力。例如,如果一个电影评论者在评论中多次说“惊人”或“糟糕”,那么该评论很可能分别是正面的或负面的。

TF-IDF

另一种表示语料库中每个文档的常见方法是对每个单词使用 tf-idf 统计量 ( 词频-逆文档频率 ) ,这是一种加权因子,我们可以使用它来代替二进制或字数表示。

有几种方法可以进行 tf-idf 转换,但简单地说,tf-idf 的目标是表示给定单词在文档(在我们的例子中是电影评论)中出现的次数相对于该单词在语料库中出现的文档数——其中出现在许多文档中的单词的值接近于 0,出现在较少文档中的单词的值接近于 1。

**注意:**现在我们已经讨论了 n 元语法,当我提到“单词”时,我实际上是指任何 n 元语法(单词序列),如果模型使用大于 1 的 n。

算法

到目前为止,我们选择将每个评论表示为一个非常稀疏的向量(很多零!)中的每个唯一的 n 元语法都有一个槽(减去出现太频繁或不够频繁的 n 元语法)。线性分类器通常在以这种方式表示的数据上比其他算法执行得更好。

支持向量机(SVM)

回想一下,线性分类器往往在非常稀疏的数据集上工作得很好(就像我们拥有的这个)。另一种可以在短训练时间内产生很好结果的算法是具有线性核的支持向量机。

下面是一个 n 元语法范围从 1 到 2 的例子:

关于支持向量机有很多很好的解释,它们比我做得好得多。如果你有兴趣了解更多,这是一个很好的教程:

[## 支持向量机教程

从例子中学习支持向量机

blog.statsbot.co](https://blog.statsbot.co/support-vector-machines-tutorial-c1618e635e93)

最终模型

这篇文章的目标是给你一个工具箱,当你试图为你的项目找到正确的模型+数据转换时,你可以试着把它们混合在一起。我发现,删除一小组停用词以及从 1 到 3 的 n 元语法范围和线性支持向量分类器给了我最好的结果。

我们突破了 90%大关!

摘要

我们已经讨论了几种可以提高 NLP 模型准确性的文本转换方法。这些技术的哪种组合会产生最好的结果取决于任务、数据表示和您选择的算法。尝试多种不同的组合来看看什么是有效的,这总是一个好主意。

我非常确信,通过这篇文章中概述的东西的不同组合,可以获得更高的准确性。我将把这个留给更有抱负的读者。:)请评论你的结果和方法!

下次

本系列的下一部分将探索构建情感分类器的深度学习方法。

基于词包和词序列的情感分析

原文:https://towardsdatascience.com/sentiment-analysis-with-word-bags-and-word-sequences-8f99593d76f8?source=collection_archive---------22-----------------------

对于一般文本,词袋方法在文本分类方面非常有效。对于本文研究的二进制文本分类任务,LSTM 处理单词序列的质量与 SVM 使用 tf-idf 向量的质量相当。但是性能是另一回事…

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将文档转换成数字向量的单词包方法忽略了文档中单词的顺序。然后,使用这种向量的分类器将为没有考虑特定单词序列对其含义和隐含目标类别的影响而付出代价。有道理。这是在考虑更新的深度学习方法时的争论,例如可以处理序列的 LSTM(长短期记忆)神经网络。在之前的文章中,我们确实已经表明,当单词序列是决定分类因素的时,使用单词包向量的朴素贝叶斯分类器(具体来说是 tf-idf)在 LSTM 的手中遭受了重创(朴素贝叶斯的 0.23 分/tf-idf 对 LSTM 的 0.91 分)。

但是文本语料库是人工。建造的目的是为了展示 LSTM 等模型中最好的一面,以及忽视上述序列的其他模型中最差的一面。LSTM 方面的这种表现会扩展到现实生活中的文本语料库吗?在现实生活中,单词序列可能不是分类的决定性因素。这就是我们在这里探讨的问题。在这篇文章中,我们从一个简单的二元分类任务开始,在后面的文章中考虑一个多标签分类任务。我们使用具有 tf-idf 向量的支持向量机(SVM)作为单词袋方法的代理,使用 LSTM 作为序列尊重方法的代理。SVM 通过 SciKit 实现,LSTM 通过 Keras 实现。当我们在这里浏览一些代码片段时,可以从 github 下载重现结果的完整代码。

1.将电影评论符号化

来自斯坦福的文本语料库大型电影评论通常用于二元情感分类,即基于评论电影是好还是坏。正面和负面评论被下载到磁盘的不同目录中。下面是“清理”文档并对其进行标记以供分析的代码片段。

  • 第 10-11 行。符号化。删除所有标点符号和 NLTK 停用词。确保所有单词/标记都以字母开头。并且只保留长度在 3 到 15 个字符之间的单词。
  • 第 15–24 行:遍历每个文件夹中的电影评论文件并标记。
  • 第 25 行:记下每个文档中的字数有助于我们稍后为 LSTM 选择合理的序列长度。对 nTokens 的百分位数统计显示,超过 86%的文档中的单词少于 200 个。
Token Summary:
min  avg    median   std     85/86/87/90/95/99         max
3    116      86      88    189/195/203/230/302/457    1388

2.打包行李和序列

LSTM 使用单词序列作为输入,而传统的分类器使用单词包,如 tf-idf 向量。手里有了每个文档作为令牌列表,我们就可以做好准备。

2.1 SVM 的 Tf-Idf 矢量

我们使用 Scikit 的 Tf-Idf 矢量器从令牌构建词汇表和文档矢量。

2.2 的序列

Keras 中的 text 处理器将每个文档转换成一个整数序列/字符串,其中的整数值表示相同处理生成的 {word:index} 字典中的实际单词。我们使用 200 长的序列,因为令牌上的统计数据显示,超过 86%的文档少于 200 个单词。在下面代码的第 8 行中,少于 200 个单词的文档将用嵌入层忽略的索引值 0 进行“post”填充(在第 3 节的嵌入层定义中设置了 mask_zero=True )。

3.模型

LSTM 通过 Keras 实现,而 SVM 通过 SciKit 实现。两者都使用相同的训练/测试分割,因此比较是公平的。整个语料库(即 10,000 个文档)的 20%被留出用于测试,同时对剩余的 40,000 个文档进行训练。

3.1 LSTM

正如在前面的文章中,我们使用最简单的 LSTM 模型,有一个嵌入层,一个 LSTM 层和输出层。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 1. A simple LSTM model for binary classification.

图 1 中的嵌入层将特征的数量从 98089(语料库中唯一单词的数量)减少到 300。LSTM 图层输出一个 150 长的矢量,该矢量将被输入到输出图层进行分类。模型本身的定义非常简单。

  • 第 4 行:嵌入层被训练成将 98089 长的 1-hot vetcors 转换成密集的 300 长的向量
  • 第 6 行:下降域有助于防止过度拟合

在下面代码的第 6 行中,通过提前停止来完成训练,以防止过度训练。最终输出图层生成一个与标注数量一样长的矢量,该矢量的 argmax 就是预测的分类标注。

3.2 SVM

SVM 的模型要简单得多,因为需要决定的运动部件和参数要少得多。这当然总是一件好事。

4.模拟

混淆矩阵和获得的 F1 分数是我们感兴趣的。有了这两种方法的预测标签,我们就可以使用 SciKit 的 API 来计算它们。

虽然我们以不同的顺序浏览了一些片段,但是运行 lstm 的 lstm_movies.py 和运行 svm 的 svm_movies.py 的完整代码在 github 上。如上一篇文章所述,各种随机种子被初始化以获得可重复性。

4.1 LSTM

运行 LSTM 与:

#!/bin/bash

echo "PYTHONHASHSEED=0 ; pipenv run python ./lstm_movies.py"
PYTHONHASHSEED=0 ; pipenv run python ./lstm_movies.py

由于早期停止,F1 分数在 6 个时期内收敛,产生约 0.87。

Using TensorFlow backend.
Token Summary:min/avg/median/std 85/86/87/88/89/90/95/99/max:
3 116.47778 86.0 88.1847205941687 189.0 195.0 203.0 211.0 220.0 230.0 302.0 457.0 1388
X, labels #classes classes 50000 (50000,) 2 ['neg', 'pos']
Vocab padded_docs 98089 (50000, 200)
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_1 (Embedding)      (None, 200, 300)          29427000  
_________________________________________________________________
lstm_1 (LSTM)                (None, 150)               270600    
_________________________________________________________________
dense_1 (Dense)              (None, 2)                 302       
=================================================================
Total params: 29,697,902
Trainable params: 29,697,902
Non-trainable params: 0
_________________________________________________________________
None
Train on 40000 samples, validate on 10000 samples
Epoch 1/50
 - 1197s - loss: 0.3744 - acc: 0.8409 - val_loss: 0.3081 - val_acc: 0.8822
Epoch 2/50
 - 1195s - loss: 0.1955 - acc: 0.9254 - val_loss: 0.4053 - val_acc: 0.8337
...
Epoch 6/50
 - 1195s - loss: 0.0189 - acc: 0.9938 - val_loss: 0.5673 - val_acc: 0.8707
Epoch 00006: early stopping
[[4506  494]
 [ 799 4201]]
              precision    recall  f1-score   support

         neg     0.8494    0.9012    0.8745      5000
         pos     0.8948    0.8402    0.8666      5000

   micro avg     0.8707    0.8707    0.8707     10000
   macro avg     0.8721    0.8707    0.8706     10000
weighted avg     0.8721    0.8707    0.8706     10000

Time Taken: 7279.333829402924

4.2 SVM

管理 SVM

#!/bin/bash

echo "PYTHONHASHSEED=0 ; pipenv run python ./svm_movies.py"
PYTHONHASHSEED=0 ; pipenv run python ./svm_movies.py

F1 值为 0.90

Token Summary. min/avg/median/std/85/86/87/88/89/90/95/99/max:
3 116.47778 86.0 88.1847205941687 189.0 195.0 203.0 211.0 220.0 230.0 302.0 457.0 1388
X, labels #classes classes 50000 (50000,) 2 ['neg', 'pos']
Vocab sparse-Xencoded 98089 (50000, 98089)
.....*
optimization finished, #iter = 59
Objective value = -6962.923784
nSV = 20647
[LibLinear][[4466  534]
 [ 465 4535]]
              precision    recall  f1-score   support

         neg     0.9057    0.8932    0.8994      5000
         pos     0.8947    0.9070    0.9008      5000

   micro avg     0.9001    0.9001    0.9001     10000
   macro avg     0.9002    0.9001    0.9001     10000
weighted avg     0.9002    0.9001    0.9001     10000

Time Taken: 0.7256226539611816

5.结论

显然,F1 值为 0.90 的 SVM 和 0.87 的 LSTM 在二元分类方面做得非常好。混淆矩阵如预期的那样表现出极好的对角优势。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 2. Both LSTM and SVM have done very well for this binary sentiment classification exercise

虽然他们在质量方面是平等的,但 LSTM 需要更长的时间——2 小时而不是不到一秒。这是一个不容忽视的巨大差异。

我们以此结束这篇文章。在下一篇文章中,我们将回顾多标签分类练习的结果以及外部单词嵌入(如 fasttext)的影响。

原载于 2019 年 1 月 28 日xplordat.com

工会的情绪

原文:https://towardsdatascience.com/sentiment-of-the-union-analyzing-presidential-state-of-the-union-addresses-with-python-2a8667a578b9?source=collection_archive---------19-----------------------

使用情感分析和 Python 工具分析总统国情咨文

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo from 271277 on Pixabay

在《宪法》第二条第三款中,美国总统被指示“向国会提交国情咨文,并建议国会考虑他认为必要和适宜的措施。”

随着特朗普 2019 年国情咨文演讲的新闻,随着时间的推移,看看这些演讲,看看我们是否能注意到自乔治·华盛顿发表第一次演讲以来的任何有趣趋势和变化,可能会很有趣。在本文中,我们将采用 Python 中的数据驱动方法,并利用情绪分析等工具来更好地了解这些演讲随时间的发展。

在一系列的 python 笔记本中,我查看了不同演讲的情感值,执行了主题建模,创建了文字云,最后通过查看每篇演讲的熵值构建了一个“说了多少”的初步衡量标准。

情感分析是自然语言处理中的一种流行工具,它通过理解文本表达的观点来帮助形成对文本的更好理解和分析。因为我们在这里考虑几种不同的方法,所以我们不会深入探讨。首先,我们将考虑用一个数字来表示每个演讲的情绪(“积极”或“消极”),然后看看主题建模是否能帮助我们获得任何进一步的见解。

在开始之前,让我们考虑一下我们可能会从将要分析的地址中得到什么。当华盛顿在 1790 年发表第一份国情咨文时,对他作为第一任总统的审查使他采取了谨慎和顺从的语气,提出了建议,而不是我们在 9/11 后从乔治·W·布什那里看到的行动呼吁。因此,我们可能会认为华盛顿讲话的情绪值相对“中性”(不赋予数值)。

这是足够的猜测。让我们看看我们的结果。我将第一个笔记本产生的情绪值绘制在下面:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

你会注意到图表右侧的一个尖峰,像一个疼痛的拇指一样突出——那是吉米·卡特总统发表的 1981 年国情咨文。如果我们忽略这段数据,其余地址的情感值会显得更加密切相关。不管怎样,当我们开始审视对总统个人的情绪变化时,我们会看一看这个特别的演讲。

让我们再往前推一点——因为我们知道每位总统演讲的情绪值,我们可以看看他们从第一次到最后一次国情咨文演讲的情绪变化。也许这将与他们总统任期的成功有一些关联。

运行这些数字,我们有以下观察结果:

  • 增幅最大的是卡特,为 106.6 亿美元。这有点令人惊讶,我们将在下面考虑它。
  • 排名第二的学校比这落后了不少:麦金利大学,33.0699999999999 美元。虽然他总统任期的开始涉及古巴危机和与西班牙的战争,但麦金利设法实现了与西班牙的和平并获得了一些领土。在他遇刺前,他总统任期的结束是乐观的,因此这一数值似乎与历史事件相符。
  • 降幅最大的是杜鲁门,为-35.07 亿。杜鲁门在二战盟军胜利后就职,并在第一任期领导了马歇尔计划和中国不确定性等理论。杜鲁门第二任期内的朝鲜战争对美国来说是一个令人沮丧的僵局,到 1952 年,杜鲁门获得了在任美国总统的最低支持率。同样,数据似乎与历史相符。
  • 罗斯福以-31 紧随杜鲁门之后。33300 . 000000000335 我们可能会想起一个矛盾的开端,罗斯福以压倒性优势战胜杜鲁门,但在大萧条期间担任总统,并创下了四届任期的纪录。他有一个多产的开始,带头主要立法和制定新政。有趣的是,1934 年的演讲并没有“向[美国人]展示一幅对世界事务完全乐观的画面。”虽然罗斯福描绘了一幅更有希望和乐观的画面,描绘了第二次世界大战结束的伟大成就和纳粹法西斯在欧洲统治的结束,但他的长篇演讲提到了“相当大的损失”、“敌人的绝望企图”以及相当于德国“分裂宣传”的“邪恶和毫无根据的谣言”。这可能是我们正在考虑的最有趣的结果,因为虽然 1945 年的演讲在许多方面肯定是积极的和充满希望的,但我们的模型可能会采用过多的令人讨厌的和负面的词汇来描述二战期间的敌人。
  • 特朗普的负面因素相当高,到他任期的第二年,负面因素的变化为-8.7699999999989。现在画出完整的轨迹并解释一切还为时过早,但关于俄罗斯调查的指控和证据的持续趋势表明,这种负面情绪的趋势可能会持续到 2019 年的国情咨文中,如果真的发生的话。

在滞胀的一年开始他的总统任期时,如果卡特成功地遏制了这种现象,那么他在讲话中表达的情绪将会显著增加,这可能是有道理的。有趣的是,卡特作为总统的最后 15 个月被包括伊朗人质危机和苏联入侵阿富汗在内的危机所破坏,而卡特本人通常被评价为低于平均水平的总统。

同样有趣的是,尽管人们一致认为波尔克总体上是一位成功的总统(尽管经常被忽视),但对他演讲的看法变化大约是 7。与此同时,不难想象,像波尔克这样的总统会在演讲中采用慎重的语气。另一方面,我们的情绪模型可能会从卡特 1981 年的演讲中获得积极和充满希望的陈述,如下面的段落:

“然而,我坚信,由于过去四年在许多国内和国际领域取得的进展,我们的国家比四年前更加强大、更加富有、更加富有同情心和更加自由。我为此感到自豪。我相信国会也应该感到自豪,因为过去四年来所取得的这么多成就都归功于国会的辛勤工作、远见卓识和通力合作。我为国会的努力和成就喝彩。”

语言本身并不反常,但卡特演讲的整体长度,加上明显充满希望和积极的语言,肯定会有助于我们的模型给演讲打分。虽然卡特没有回避提及困难,但他讲话的意图是描绘四年来的进步。很自然,卡特想总结他认为是他的政府的决定性成就,并为未来设定一个积极的基调。这导致了一个比平常更冗长和更有希望的演讲。

在第二个笔记本中,我进行了主题建模,这是一种帮助我们发现出现在文档和文本中的抽象主题的统计建模。我在演讲的子集上使用了两个模型,潜在狄利克雷分配(LDA)和潜在语义索引(LSI),保留了特朗普给出的最后两个地址。

对于那些寻找这两个模型的技术解释的人,你可以在马志威的文章中找到对 LDA 和 LSI 的很好的解释。在这里,我将主要关注他们能告诉我们什么关于我们感兴趣的演讲。LDA 模型为我们提供了以下主题群(LSI 模型的输出可以在笔记本 2 中找到):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Topics produced by the LDA Model

如果我们跳过那些在所有话题中明显无处不在的词(“美国”、“美国”、“国会”、“年份”),那么这些话题能做的就是让我们对演讲中使用的语言类型有所了解。不幸的是,值得注意的是,该模型并没有给我们太多的主题,例如“农业”或“关系”。另一方面,“必须”、“伟大”和“人民”等词可以告诉我们更多关于演讲语气的信息,以及它们在历史上如何被用作更新和呼吁行动,激发美国人对自己国家的强烈自豪感。

在我们探索的下一部分,我们将试图通过单独计算每个地址的熵来构建一个(非常)基本的“总统说了多少”的度量。在信息论中,被定义为随机(random)数据源产生信息的平均速率。在这种情况下,熵表达了我们对一个演讲的信息内容的期望,或者它解决了多少不确定性。

就我们的目的而言,我们可以认为熵值是文本的简洁程度。一个演讲的熵值越高,它就越不简洁,因此“说”得越多。我们将把这种想法作为起点,从那里开始。以下是每场演讲的熵图,从华盛顿开始,到特朗普结束:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Entropy of State of the Union Addresses

不要太深入,值得注意的是,平均而言,随着时间的推移,熵值似乎会随着相当数量的下降而增加。然而,这些值下降得足够明显,以至于我们可能会说,从早期到后期,熵显著增加了。高熵演讲的一个特点是更长的长度,但在这个笔记本上的进一步探索表明,这并不能解释全貌。如果你有兴趣看到一些进一步的分析,或许你自己也可以继续下去,请查看题为“熵”的笔记本。

在探索的最后一步,我生成了一些文字云来可视化以下内容:

  • 所有 SOTU 地址的汇编
  • 比较最早的 10 个地址和最晚的 10 个地址
  • 比较一下奥巴马的演讲和特朗普的两个演讲

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

WordCloud of compilation of SOTU addresses

如果我们考虑所有地址的词云,我们不应该太惊讶最突出的词是最普遍的,广泛适用于美国人民:“美国”,“美国”,“国家”,“新”和“人民”是特色。我们在主题建模中看到的单词,如“must”和“will”也出现了。

与此同时,虽然它们的优先地位较低,但近年来引发大量辩论且有历史根源的话题也出现了——这些话题包括“毒品”、“移民”和“恐怖分子”。

接下来,我们将查看 10 个最老的地址和 10 个最新的地址。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将最老的地址与最新的地址进行比较,会发现一些显著的变化。在最新的演讲词云中,“美国”几乎被完全删除,而“必须”、“伟大”和“国家”的出现比以前多得多。“利益”和“国家”这两个词也消失了,这表明从早期到当代总统的演讲中出现了一些有趣的修辞变化。

如果我们记得总统任期最初几年的不稳定性,那么呼吁采取行动将比当时更成为当今世界的常态是有道理的——此外,当代话语引发了大量利用美国人自豪感的言论,解释了“伟大”一词。“利益”和“国家”等词的消失可能标志着一种转变,即远离建国之父们如此深入思考的关于民族国家功能的更多理论论述。

最后,让我们比较一下我们最近的两位总统:巴拉克·奥巴马和唐纳德·特朗普发表的国情咨文的文字云。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

值得注意的是,在奥巴马的词汇云中,“我们”、“制造”、“新”、“帮助”、“工作”和“每一个”出现的次数更多。特朗普的云以“美国”和“国家”为特色,更强调“人民”和“国家”。我们还可以轻松地发现“毒品”这个词,尽管在奥巴马的云中我们不能。虽然一些最重要的词汇是通用的,但两朵云彩之间的差异及其隐含的修辞暗示表明了奥巴马和特朗普的利益和政策的差异。

奥巴马是积极变革的支持者,也是一位经常利用演讲(正如他在竞选中所做的那样)在听众中产生社区感的政治家,这解释了“我们”和“每一个”等词的存在,而他的国内医疗政策和对这一政策的关注可能解释了“帮助”等词的存在。我们在特朗普的云中注意到的词语反映了他演讲中相当大剂量的民族主义。“will”这个词在两朵云彩中占主导地位,暗示着两位总统的承诺。

作为总结,我们分析了自乔治·华盛顿以来历届总统发表的国情咨文,首先使用一种基本的情绪测量方法来观察演讲中的积极和消极情绪,以及每位总统在这些价值观上的转变。然后,我们考虑主题建模,看看我们是否可以对国情咨文中感兴趣的主题进行推断。接下来,我们认为熵是可压缩性的度量,也是语音“内容”的基本度量。最后,我们使用 WordClouds 来研究这些演讲中与所有总统密切相关的话题,以及一些有趣的团体和个人之间的差异。

像 NLP 这样的工具可以帮助我们分析从演讲到书籍的历史文献中的有趣趋势,并开发新的见解。总统的国情咨文很重要,因为它能告诉我们美国历史上的时事状况,并描绘出乐观和悲观的图景。虽然有帮助,但如果我们不花时间自己检查文件,对形势的纯技术分析可能会导致我们得出误导性的结论,就像罗斯福的情况一样。在我们前进的过程中,我们应该继续使用情感分析等工具,因为它们可以提供强大的洞察力,但请记住,在分析文本和演讲时,尤其是在分析文本和演讲时,有必要考虑大量的上下文和修辞因素,这些因素通常无法像人类一样理解。

来源:

[1] G .华盛顿,第一次向国会发表年度演说 (1790)。

[2] J .卡特,国情咨文 (1981)。

[3]f·罗斯福,国情咨文 (1934)。

[4]f·罗斯福,国情咨文 (1945)。

[5] 威廉·麦金利,维基百科。

[6] 哈里·S·杜鲁门,维基百科。

[7] 富兰克林·罗斯福总统任期,维基百科。

[8] E. Ma, 2 潜在的降维和主题建模方法 (2018),走向数据科学。

情感保持词嵌入

原文:https://towardsdatascience.com/sentiment-preserving-word-embeddings-9bb5a45b2a5?source=collection_archive---------19-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

单词嵌入是一种使用连续值向量将单词映射到空间中的技术,使得具有相似上下文的单词看起来彼此更接近。通常,这是通过获取大量数据,然后使用 Word2Vec 或 GloVE 或其他算法从中提取单词嵌入来完成的。这些算法有助于捕捉不同单词的语义和句法上下文,但在涉及情感时会受到很大影响。

让我们看一个例子。这里我们来看单词嵌入空间中单词**“good”**的 10 个最近邻。我们使用在谷歌新闻上训练的 Word2Vec 模型,有 300 个维度。下面是查看前 10 个邻居的代码。

*import* gensim.models.keyedvectors *as* word2vec

wordVectorModel = word2vec.KeyedVectors.load_word2vec_format("GoogleNews-vectors-negative300.bin",
                                                                 binary=*True*)
neighbors = list(wordVectorModel.similar_by_word("good", topn=10))
print(neighbors)

这为我们提供了以下输出。

[('great', 0.7291510105133057), ('bad', 0.7190051078796387), ('terrific', 0.6889115571975708), ('decent', 0.6837348937988281), ('nice', 0.6836092472076416), ('excellent', 0.644292950630188), ('fantastic', 0.6407778263092041), ('better', 0.6120728254318237), ('solid', 0.5806034803390503), ('lousy', 0.5764201879501343)]

从这个结果可以明显看出,当前的 Word2Vec 模型并没有真正捕获情感信息。第二个最接近“好”的词是
“坏”,它们在情感上是相反的。

解决方案

[1]为这个问题提供了一个非常新颖的解决方案。在这篇博客中,我们将讨论他们的方法,然后展示“好”的最近邻居,看看这种方法是否有效。

这种方法背后的主要思想是更新当前可用的单词嵌入,使得在单词的最近邻居中,情感上相似的单词看起来更接近。这是按照两步程序完成的。

最近邻排序

在这一步骤中,他们使用了一种叫做 E-ANEW 的情感词典,这种词典用于研究英语单词情感规范的扩展版本。它包含大约 13000 个单词,每个单词有 1-9 分,其中 1 代表非常消极,5 代表中性,9 代表非常积极。

首先,他们基于当前可用的单词嵌入选择前 K 个最近邻,并根据它们的余弦相似性对它们进行降序排列。然后根据参考词与该列表中词的情感得分的绝对差值,对该列表进行重新排序。这种重新排序促进情感上相似的单词更接近参考单词。

细化模型

在为情感词典中的所有单词创建排序列表之后,他们更新单词嵌入。本次更新是在牢记以下几点的情况下完成的。

  1. 更接近情感上相似的邻居
  2. 远离不同的邻居,和
  3. 离原始向量不太远。

在更新单词 embeddings 之后,我们得到单词**“good”的如下结果。**如果您更改训练参数,这些结果可能会有所不同。

[('astonishing', 0.9998810291290283), ('unbelievable', 0.9998570680618286), ('respectable', 0.9998552203178406), ('solid', 0.9998213648796082), ('commendable', 0.9998155236244202), ('decent', 0.9998145699501038), ('excellent', 0.9998089075088501), ('incredible', 0.9997923374176025), ('amazing', 0.9997886419296265), ('exciting', 0.9997859001159668)]

这个方法的代码可以在[2]中找到。值得注意的是,它们的词嵌入也保留了情感,可以在情感分析性能方面有很大帮助。

参考文献

[1]https://www.aclweb.org/anthology/D17-1056

[2]https://github.com/wangjin0818/word_embedding_refine

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值