如何用Python做舆情时间序列可视化

Python016

如何用Python做舆情时间序列可视化,第1张

如何批量处理评论信息情感分析,并且在时间轴上可视化呈现?舆情分析并不难,让我们用Python来实现它吧。

痛点

你是一家连锁火锅店的区域经理,很注重顾客对餐厅的评价。从前,你苦恼的是顾客不爱写评价。最近因为餐厅火了,分店越来越多,写评论的顾客也多了起来,于是你新的痛苦来了——评论太多了,读不过来。

从我这儿,你了解到了情感分析这个好用的自动化工具,一下子觉得见到了曙光。

你从某知名点评网站上,找到了自己一家分店的页面,让助手把上面的评论和发布时间数据弄下来。因为助手不会用爬虫,所以只能把评论从网页上一条条复制粘贴到Excel里。下班的时候,才弄下来27条。(注意这里我们使用的是真实评论数据。为了避免对被评论商家造成困扰,统一将该餐厅的名称替换为“A餐厅”。特此说明。)

好在你只是想做个试验而已,将就了吧。你用我之前介绍的中文信息情感分析工具,依次得出了每一条评论的情感数值。刚开始做出结果的时候,你很兴奋,觉得自己找到了舆情分析的终极利器。

可是美好的时光总是短暂的。很快你就发现,如果每一条评论都分别运行一次程序,用机器来做分析,还真是不如自己挨条去读省事儿。

怎么办呢?

序列

办法自然是有的。我们可以利用《贷还是不贷:如何用Python和机器学习帮你决策?》一文介绍过的数据框,一次性处理多个数据,提升效率。

但是这还不够,我们还可以把情感分析的结果在时间序列上可视化出来。这样你一眼就可以看见趋势——近一段时间里,大家是对餐厅究竟是更满意了,还是越来越不满意呢?

我们人类最擅长处理的,就是图像。因为漫长的进化史逼迫我们不断提升对图像快速准确的处理能力,否则就会被环境淘汰掉。因此才会有“一幅图胜过千言万语”的说法。

准备

首先,你需要安装Anaconda套装。详细的流程步骤请参考《 如何用Python做词云 》一文。

助手好不容易做好的Excel文件restaurant-comments.xlsx,请从这里下载。

用Excel打开,如果一切正常,请将该文件移动到咱们的工作目录demo下。

因为本例中我们需要对中文评论作分析,因此使用的软件包为SnowNLP。情感分析的基本应用方法,请参考《如何用Python做情感分析?》。

到你的系统“终端”(macOS, Linux)或者“命令提示符”(Windows)下,进入我们的工作目录demo,执行以下命令。

pip install snownlp

pip install ggplot

运行环境配置完毕。

在终端或者命令提示符下键入:

jupyter notebook

如果Jupyter Notebook正确运行,下面我们就可以开始编写代码了。

代码

我们在Jupyter Notebook中新建一个Python 2笔记本,起名为time-series。

首先我们引入数据框分析工具Pandas,简写成pd以方便调用。

import pandas as pd

接着,读入Excel数据文件:

df = pd.read_excel("restaurant-comments.xlsx")

我们看看读入内容是否完整:

df.head()

结果如下:

注意这里的时间列。如果你的Excel文件里的时间格式跟此处一样,包含了日期和时间,那么Pandas会非常智能地帮你把它识别为时间格式,接着往下做就可以了。

反之,如果你获取到的时间只精确到日期,例如"2017-04-20"这样,那么Pandas只会把它当做字符串,后面的时间序列分析无法使用字符串数据。解决办法是在这里加入以下两行代码:

from dateutil import parser

df["date"] = df.date.apply(parser.parse)

这样,你就获得了正确的时间数据了。

确认数据完整无误后,我们要进行情感分析了。先用第一行的评论内容做个小实验。

text = df.comments.iloc[0]

然后我们调用SnowNLP情感分析工具。

from snownlp import SnowNLP

s = SnowNLP(text)

显示一下SnowNLP的分析结果:

s.sentiments

结果为:

0.6331975099099649

情感分析数值可以正确计算。在此基础上,我们需要定义函数,以便批量处理所有的评论信息。

def get_sentiment_cn(text):

s = SnowNLP(text)return s.sentiments

然后,我们利用Python里面强大的apply语句,来一次性处理所有评论,并且将生成的情感数值在数据框里面单独存为一列,称为sentiment。

df["sentiment"] = df.comments.apply(get_sentiment_cn)

我们看看情感分析结果:

df.head()

新的列sentiment已经生成。我们之前介绍过,SnowNLP的结果取值范围在0到1之间,代表了情感分析结果为正面的可能性。通过观察前几条数据,我们发现点评网站上,顾客对这家分店评价总体上还是正面的,而且有的评论是非常积极的。

但是少量数据的观察,可能造成我们结论的偏颇。我们来把所有的情感分析结果数值做一下平均。使用mean()函数即可。

df.sentiment.mean()

结果为:

0.7114015318571119

结果数值超过0.7,整体上顾客对这家店的态度是正面的。

我们再来看看中位数值,使用的函数为median()。

df.sentiment.median()

结果为:

0.9563139038622388

我们发现了有趣的现象——中位数值不仅比平均值高,而且几乎接近1(完全正面)。

这就意味着,大部分的评价一边倒表示非常满意。但是存在着少部分异常点,显著拉低了平均值。

下面我们用情感的时间序列可视化功能,直观查看这些异常点出现在什么时间,以及它们的数值究竟有多低。

我们需要使用ggplot绘图工具包。这个工具包原本只在R语言中提供,让其他数据分析工具的用户羡慕得流口水。幸好,后来它很快被移植到了Python平台。

我们从ggplot中引入绘图函数,并且让Jupyter Notebook可以直接显示图像。

%pylab inlinefrom ggplot import *

这里可能会报一些警告信息。没有关系,不理会就是了。

下面我们绘制图形。这里你可以输入下面这一行语句。

ggplot(aes(x="date", y="sentiment"), data=df) + geom_point() + geom_line(color = 'blue') + scale_x_date(labels = date_format("%Y-%m-%d"))

你可以看到ggplot的绘图语法是多么简洁和人性化。只需要告诉Python自己打算用哪个数据框,从中选择哪列作为横轴,哪列作为纵轴,先画点,后连线,并且可以指定连线的颜色。然后,你需要让X轴上的日期以何种格式显示出来。所有的参数设定跟自然语言很相似,直观而且易于理解。

执行后,就可以看到结果图形了。

在图中,我们发现许多正面评价情感分析数值极端的高。同时,我们也清晰地发现了那几个数值极低的点。对应评论的情感分析数值接近于0。这几条评论,被Python判定为基本上没有正面情感了。

从时间上看,最近一段时间,几乎每隔几天就会出现一次比较严重的负面评价。

作为经理,你可能如坐针毡。希望尽快了解发生了什么事儿。你不用在数据框或者Excel文件里面一条条翻找情感数值最低的评论。Python数据框Pandas为你提供了非常好的排序功能。假设你希望找到所有评论里情感分析数值最低的那条,可以这样执行:

df.sort(['sentiment'])[:1]

结果为:

情感分析结果数值几乎就是0啊!不过这里数据框显示评论信息不完全。我们需要将评论整体打印出来。

print(df.sort(['sentiment']).iloc[0].comments)

评论完整信息如下:

这次是在情人节当天过去的,以前从来没在情人节正日子出来过,不是因为没有男朋友,而是感觉哪哪人都多,所以特意错开,这次实在是馋A餐厅了,所以赶在正日子也出来了,从下午四点多的时候我看排号就排到一百多了,我从家开车过去得堵的话一个小时,我一看提前两个小时就在网上先排着号了,差不多我们是六点半到的,到那的时候我看号码前面还有才三十多号,我想着肯定没问题了,等一会就能吃上的,没想到悲剧了,就从我们到那坐到等位区开始,大约是十分二十分一叫号,中途多次我都想走了,哈哈,哎,等到最后早上九点才吃上的,服务员感觉也没以前清闲时周到了,不过这肯定的,一人负责好几桌,今天节日这么多人,肯定是很累的,所以大多也都是我自己跑腿,没让服务员给弄太多,就虾滑让服务员下的,然后环境来说感觉卫生方面是不错,就是有些太吵了,味道还是一如既往的那个味道,不过A餐厅最人性化的就是看我们等了两个多小时,上来送了我们一张打折卡,而且当次就可以使用,这点感觉还是挺好的,不愧是A餐厅,就是比一般的要人性化,不过这次就是选错日子了,以后还是得提前预约,要不就别赶节日去,太火爆了!

通过阅读,你可以发现这位顾客确实有了一次比较糟糕的体验——等候的时间太长了,以至于使用了“悲剧”一词;另外还提及服务不够周到,以及环境吵闹等因素。正是这些词汇的出现,使得分析结果数值非常低。

好在顾客很通情达理,而且对该分店的人性化做法给予了正面的评价。

从这个例子,你可以看出,虽然情感分析可以帮你自动化处理很多内容,然而你不能完全依赖它。

自然语言的分析,不仅要看表达强烈情感的关键词,也需要考虑到表述方式和上下文等诸多因素。这些内容,是现在自然语言处理领域的研究前沿。我们期待着早日应用到科学家们的研究成果,提升情感分析的准确度。

不过,即便目前的情感分析自动化处理不能达到非常准确,却依然可以帮助你快速定位到那些可能有问题的异常点(anomalies)。从效率上,比人工处理要高出许多。

你读完这条评论,长出了一口气。总结了经验教训后,你决定将人性化的服务贯彻到底。你又想到,可以收集用户等候时长数据,用数据分析为等待就餐的顾客提供更为合理的等待时长预期。这样就可以避免顾客一直等到很晚了。

祝贺你,经理!在数据智能时代,你已经走在了正确的方向上。

下面,你该认真阅读下一条负面评论了……

1、If语句详解与实践

之前已经用过很多次If函数了,这边我再做一个简单介绍和一些新内容的补充吧,If函数的底层逻辑就是用来判断,如果满足条件则执行下面的语句。

基本的语法逻辑如下,注意记得写冒号及代码前的缩进:

if 条件:

代码1

else:

代码2

1

2

3

4

其中两个注意点,之前也提过了,就是缩进与英文格式的标点符号,有的时候,你忘记缩进或者冒号是中文格式的时候,程序就会报错,不过Pycharm和Spyder都会在那一行提醒你这一行的写法有问题,所以倒也不用太担心。

现在我们再来看看之前写过这个代码,是不是会感觉清晰很多呢。

score = 100

year = 2018

if (score <0) and (year == 2018):

print('录入数据库')

else:

print('不录入数据库')

1

2

3

4

5

6

我们下面再补充些内容,其实掌握上面的内容已经完全足够了,下面的只是作为一个知识点的补充。比如你考试考了80分,最简单的是:

score = 85

if score >= 60:

print('及格')

else:

print('不及格')

1

2

3

4

5

我相信现在大家看这个代码已经完全没有问题了,输出肯定是‘及格’。那如果我除了想判断是否及格外,还想看它是否优秀(大于80分),则输出‘优秀’,该怎么弄呢。

score = 55

if score >= 80:

print('优秀')

elif (score >= 60) and (score <80):

print('及格')

else:

print('不及格')

1

2

3

4

5

6

7

这边唯一的一个不同,就是中间加入了一个elif,这个其实就是elseif的缩写,用来提供多个结果使用的,

其实这个我做项目的时候基本没有用过,大家简单了解下即可。

2、For语句详解与实践

For语句之前有提到过一次,它的重要程度可以说仅次于If语句了,它的底层逻辑是循环,其实While的底层逻辑是循环,不过还是For用的更加普遍些。

For语句的常见使用格式为,注意记得写冒号及代码前的缩进:

for i in 区域:

代码

1

2

先举个之前讲列表的时候讲过的例子:

class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']

for i in class1:

print(i)

1

2

3

用大白话来说就是:

列表class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']

对于class1中的所有元素i:

我们都把它打印输出出来

1

2

3

这个输出代码为:

丁一

王二麻子

张三

李四

赵五

1

2

3

4

5

这个i可以换成任何东西,比如你换成j,换成一个字符串,只要和下面的print()里面的内容匹配即可。

比如我们可以写:

class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']

for haha in class1:

print(haha)

1

2

3

这样输出的结果其实是一样的。

For语句还通常与range()函数合用,range函数的话其实就是一个类似于list的东西,只不过它可能更像list的长度,你想循环多少次,在range的括号里填写几就可以,比如我写for i in range(3),那么它就是循环3次:

for i in range(3):

print('hahaha')

1

2

这个它就会输出三行‘hahaha’。

我担心大家可能会对这个for i in range(3)中的i还有疑惑,刚刚i不是代表列表里的每一个元素吗,这边这个i又是什么意思呢?这边我给大家做一个偷懒的总结:

(1)对于"for i in 区域"来说,如果说这个区域是一个列表,那么那个i就表示这个列表里的每一个元素;

(2)对于"for i in 区域"来说,如果说这个区域是一个range(n),那么那个i就表示0到n -1这n个数字,之前提到过,python中序号都是从0开始的,所以这边也是从0开始,到n - 1结束。

(3)对于"for i in 区域"来说,如果说这个区域是一个字典,那么i表示的就是字典的中的键(了解即可,很长一段时间用不到)

还有个非常重要的知识点:for i in range(5)的话,它的确会循环5次,但要注意,在python中,第一个元素的序号其实是0,所以如果我们输入如下代码:

for i in range(5):

print(i)

1

2

那么输出的结果是从0开始的,也就是0到4

0

1

2

3

4

1

2

3

4

5

这时候你可能要问,这玩意有什么用?下面我就以舆情监控中的实战来给大家讲解下for语句在爬虫实战中的应用:

title = ['标题1','标题2','标题3','标题4','标题5']

for i in range(len(title)): #len(title)表示一个有多少个新闻,这里是5

print(str(i+1) + '.' + title[i]) #这个其实把字符串进行一个拼接

1

2

3

上面这几行代码已经很大程度就是你做项目实战用到的代码了,暂时看着有点晕也没有关系,我在教学视频里会详细介绍下的。我先用大白话来解释下这几行代码在干嘛:

爬到了一些新闻标题,放到了title这个列表里

用len(title)来获取一共有多少条新闻,并利用for和range语句来进行循环:

打印输出新闻标题,并且在前面加上序号

1

2

3

输出结果如下图所示:

其中有几个小注意点,

(1)range(len(title))这边就相当于range(5),因为len(title)就等于5,所以for i in range(len(title))就是循环5次,这里的i就表示数字0-4。

(2)为什么要写str(i + 1),因为我们要标序号,'标题1’是字符串形式的,而i是数字,我们讲过数字和字符串不能直接相加,所以要用str函数进行下转换。

(3)至于为什么不是str(i),而是str(i + 1)。是因为之前讲列表的时候提到过,在编程中,第一个序号都是0,比如之前列表里讲过的class1[0]表示“丁一”一样,这边如果写str(i)的话,那么输出的第一个序号就是“0.标题1”了。

(4)因为这里的i就表示数字0-4,title[i]的话,表示列表中的第i+1个元素,所以title[0]的话就表示第1个元素,title[4]就表示第5个元素。

通过for循环和range()函数和len()函数的联合使用,可以同时打印多个列表中的元素,代码如下:

# 在实战中的应用(可以同时打印多个列表中的内容)

title = ['标题1', '标题2', '标题3', '标题4', '标题5']

href = ['网址1', '网址2', '网址3', '网址4', '网址5']

for i in range(len(title)): # len(title)表示一个有多少个新闻,这里是5;这里的i就表示数字0-4

print(str(i+1) + '.' + title[i]) # 这个其实把字符串进行一个拼接

print(href[i])

1

2

3

4

5

6

3、While语句详解与实践

While的底层逻辑也是循环,它和For的特点不一样,最大的区别是For知道循环次数,而While的话则是不清楚循环次数。

其使用格式为,注意要写冒号以及代码前的缩进:

while 条件:

要执行的的代码

1

2

举个例子给大家看下:

a = 1

while a <3:

print(a)

a = a + 1 #或者写成 a += 1

1

2

3

4

它白话的意思就是:

首先将1赋值给a

当 a 小于3的时候:

打印输出a

a 在原来的基础上加上1

1

2

3

4

a一开始等于1,满足小于3的条件,会打印输出1,然后a加上1等于2,此时a仍然小于3,所以仍然会执行打印输出的命令,此时打印输出2,然后a在2的基础上加上1等于3,此时a已经不满足小于3的条件了,那么循环此时便终止了。最后输出如下:

1

2

1

2

大家可以试着把数字3换成别的数试试看。

其实我们之后大多情况下用到While的时候,就是让While来一直循环(如果用for i in range(n),无论n多大,那么早晚都有结束的时候),这个在爬虫实战中的具体应用是:当每爬完一次,就自动进行下一次爬取,实现24小时不间断爬取。那么While如何能实现一直循环呢?

具体的方法其实很简单,那就用while True进行永久循环。

while True:

代码块

1

2

给大家截个图看下,下面这张图就是最终的代码效果,这个while True就是舆情监控系统实现24小时不间断爬取的秘诀,有个注意点,这个True得大写首字母,之后讲到的时候再详细介绍:

大家如果想停止while True的不停的循环,可以在点击右上角的红色终止按钮即可。我当初自己学的时候,写过这么两行代码

学会python可以做的兼职:

1、爬虫

首先,除了Python的语法基础的之外的必修课就是web开发和爬虫的内容了。如果是想依靠这两个方向来赚钱的话,就必须要清楚的知道开发什么或者爬什么数据才能赚钱。如果你都不知道的话,你可以开个网店,或者去猪八戒做服务的外包。

不管是web开发还是爬虫,都需要找到好的项目。最好的就是帮一些证券的人员抓一些财经的新闻或者是舆情相关的数据。这个内容开发完了,只要不会出现问题的话,基本上月入3-5k是没有什么问题的。需要自己买一个云主机,一个月的成本也就是200-300左右。

2、量化交易

用Python来完成量化交易的话还是非常方便的,但是对于新手来说内容会比较难。先解释一下什么是量化交易,也就是做一个数据挖掘的过程。不同的就是你可以用手中可以用的模型来选股,选时间,资金管理就是我们要做的特征工程。如果在量化交易中要追求稳定的收益的话,是可以考虑一下在各种虚拟币交易市场搬搬转。

3、代写程序或者是外包

电商平台很多代谢程序的,几百块就可以搞定LAMP的管理系统,但是这种基本都是大学生的毕设,所以可以照猫画虎的开一家这样的店铺。

首先毕设就是毕设,不要帮别人写论文。因为论文后期是一直要改稿子的,本科的毕设都是研发类型的,这类的门槛比较低。通用代码很多,模板很多。

Python学习路线图: