8.3 基于时间信息的文本数据可视化

除了单纯的文本信息外,结合其他方面的信息对文本数据进行考量可以更加全面深入的理解文本数据,时间信息就是不容忽视的一种,在邮件、新闻、电子商务平台顾客评论等文本信息中几乎都会涉及到相关的时间信息,结合时间信息可以了解文本内容的变化规律,包含时间信息的文本数据可视化近年来也受到越来越多的关注。

本节仍以 4.1 节使用的亚马逊中国站上热门商品 “kindle” 的评论语料作为分析实例,语料已经被保存为 CSV 文件“kindle_corpus.csv”,并上传到 Jupyter Notebook 文件列表。新建一个 notebook,读取文本数据,本节使用 pandas 库定义的 read_csv 函数直接将相关数据读取为 dataframe 格式。


In [1]:import pandas as pd
       df_reviews = pd.read_csv('kindle_corpus.csv')
       df_reviews.head()
Out[1]:@todo 补充截图 9.3.1-1

可以看到函数 read_csv 将 CSV 文件直接读取为 dataframe 格式,该函数定义在 pandas.io.parsers 模块内,调用时有诸多参数可供调节,最简单的调用方式为:read_csv(filepath_or_buffer, names=None, usecols=None)

参数说明:

filepath_or_buffer:待读取的文件路径或者支持 read 方法的对象

names:列名称列表,如果文件不包含列名,使用该参数进行命名

usecols:需要读取的列名称列表,当只需读取部分列时,使用该参数进行选择,列表中包含的列名称(或者列编号)将会被读取

使用内置函数 min 和 max 返回时间列的最小值和最大值,查看评论文本的时间跨度


In [2]:[min(df_reviews.pubdate),max(df_reviews.pubdate)]
Out[2]:['2014-10-03', '2015-08-24']

8.3.1 热图

热图可以用颜色变化来反映二维矩阵或表格中的数据信息,直观地将数据值的大小以定义的颜色深浅表示出来,时间是常用的维度信息。本节我们使用数据可视化库 seaborn 中 matrix 模块下的函数 heatmap 进行热图的绘制,该函数可以将二维数据矩阵对应转化为热图,调用方式为:heatmap(data, vmin=None, vmax=None, annot=None, fmt='.2g', linewidths=0, linecolor='white', xticklabels=True, yticklabels=True)

部分参数说明:

data:用于绘制热图的二维数据矩阵,取值类型应为可以转为 n 维数组的二维数据集,如果传入的是 dataframe 结构的数据,则直接使用 dataframe 的行列信息作为热图的坐标信息

vmin/vmax:用于锚定热图的颜色,若不进行设置,则根据实际数据和其他参数自行选择颜色

annot:是否给热图添加数值注释,有以下两种取值方式:
(1)布尔型:若取值为 True,则用参数 data 中的数据对热图进行数值注释
(2)二维数据矩阵:和参数 data 相同维度的矩阵,用该矩阵中的数值对热图进行数值注释

fmt:传入 annot 参数进行数值注释时,利用该参数设置注释的字符串格式,可选值及含义可参考 https://docs.python.org/2/library/string.html#format-specification-mini-language

linewidths:划分各个单元格的线条的宽度

linecolor:划分各个单元格的线条的颜色

xticklabels:取值为 True 时,热图上将对应显示数据框列名,或者自行指定名称列表

yticklabels:取值为 True 时,热图上将对应显示数据框行名,或者自行指定名称列表

9.3.1.1 评论数热图

在使用 heatmap 绘图之前,需要将数据转换为相应的二维矩阵,如果需要绘制不同年度各个月份的评论数热图,就需要在原始数据的基础上计算不同年度各个月份的累计评论数,为了便于计算,先将原时间数据由“年-月-日”拆分为“年”、“月”、“日”三列,并添加评论数计数列:


In [3]:# 创建空列表用于存放拆分得到的年、月、日数据
       year=[]
       month=[]
       day=[]
       for i in df_reviews.pubdate:
           year.append(i.split("-")[0]) # 拆分出年度数据
           month.append(i.split("-")[1]) # 拆分出月度数据
           day.append(i.split("-")[2]) # 拆分出日数据
       # 将拆分得到的数据保存到原数据框中
       df_reviews["year"]=year
       df_reviews["month"]=month
       df_reviews["day"]=day
       # 创建评论计数列,每条评论对应的都是“1”
       df_reviews["count"]=len(df_reviews)*[1]
       查看新的数据框
       df_reviews.head()
Out[3]:@todo 补充截图 9.3.1-2

得到以上新数据框后,可以通过创建数据透视表的方式得到所需的二维矩阵,pandas 库的函数 pivot_table 即可实现这一需求,在调用该函数之前,先做一个简单的介绍:

pivot_table 函数位于 pandas.tools.pivot 模块,可以为数据框创建数据透视表,调用方式为:pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')

部分参数说明:

data:用于创建数据透视表的数据框

values:可选参数,指定用于聚合的数据列

index:数据透视表的行

columns:数据透视表的列

aggfunc:数据聚合函数,默认取值为'mean',即求均值

fill_value:缺失值的替换值

下面以数据框中“year”和“month”为数据透视表的两个维度,评论计数“count"为汇总对象,构造数据透视表 dataset_ym :


In [4]:dataset_ym=pd.pivot_table(df_reviews, values = 'count', index = 'year', columns = 'month',aggfunc='sum')
       dataset_ym
Out[4]:@todo 补充截图 9.3.1-3

可以看到,得到的数据透视表清晰的展示了不同年份的各个月份的累计评论数,利用该数据透视表就可以直接绘制相应的热图了:


In [5]:%matplotlib inline
       import seaborn as sea
       sea.heatmap(dataset_ym,linewidths=.5)
Out[5]:<matplotlib.axes._subplots.AxesSubplot at 0x7fd04a2ed990>
@todo 补充截图 9.3.1-4
In [6]:sea.heatmap(dataset_ym,annot=True,fmt="n",linewidths=.5)
Out[6]:<matplotlib.axes._subplots.AxesSubplot at 0x7fd049580b90>
@todo 补充截图 9.3.1-5

下面以数据框中“month”和“day”为数据透视表的两个维度,评论计数“count"为汇总对象,构造数据透视表 dataset_md ,并绘制热图:


In [7]:dataset_md=pd.pivot_table(df_reviews, values = 'count', index = 'month', columns = 'day',aggfunc='sum')
       dataset_md
Out[7]:@todo 补充截图 9.3.1-6
In [8]:sea.heatmap(dataset_md,linewidths=.5)
Out[8]:<matplotlib.axes._subplots.AxesSubplot at 0x7fd0480fe110>
@todo 补充截图 9.3.1-7

从热图可以看出,7 月初和 12 月中旬累计评论量显著高于其他时间段。

9.3.1.2 热门词汇出现次数热图

除了统计不同时间的累计评论数,还可以计算不同时间热门词汇出现的次数,下面对评论文本进行简单的分词处理,并统计热门词汇“闪屏”出现的次数:


In [9]:# 简单分词处理,将分词结果保存在数据框 "words" 列
       import jieba
       df_reviews["words"]=[list(jieba.cut(i)) for i in df_reviews["content"]]
       # 统计每条评论热门词汇"闪屏"出现次数,并将统计结果保存在数据框 "word_count" 列
       df_reviews["word_count"]=[i.count(u"闪屏") for i in df_reviews["words"]]
       # 生成数据透视表 dataset_md_words
       dataset_md_words=pd.pivot_table(df_reviews, values = 'word_count', index = 'month', columns = 'day',aggfunc='sum')
       dataset_md_words
Out[9]:@todo 补充截图 9.3.1-8
In [10]:sea.heatmap(dataset_md_words,linewidths=.5)
Out[10]:<matplotlib.axes._subplots.AxesSubplot at 0x7fd042bd0890>
@todo 补充截图 9.3.1-9

8.3.2 折线图

8.3.2.1 累计计数趋势图

在绘制趋势图之前需要对数据框中的表示时间的列“pubdate”进行类型转换,可以查看一下,原始的时间数据被存储为字符串:


In [11]:type(df_reviews["pubdate"][0])
Out[11]:str

为了绘制时间趋势图,我们需要将其转换为时间类型,这里用到的是 datetime 时间处理模块中的 strptime 函数,调用方式如下:


In [12]:from datetime import datetime
        print datetime.strptime(df_reviews["pubdate"][0],"%Y-%m-%d")

        2015-07-11 00:00:00

可以看到,函数 strptime 有两个需要传入的参数,一是待格式转换的字符串,一是需要转换成的时间格式,下面就利用该函数对“pubdate”列所有的时间字符串进行格式转换,并保存到新列 time 中:


In [13]:df_reviews["time"]=[datetime.strptime(i,"%Y-%m-%d") for i in df_reviews["pubdate"]]
        df_reviews.time.head()
Out[13]:0   2015-07-11
        1   2015-07-08
        2   2015-07-01
        3   2015-07-12
        4   2015-08-05
        Name: time, dtype: datetime64[ns]

想要绘制不同时点累计评论数,有一种方式就是先对不同时点的评论数进行汇总,再利用汇总结果绘制折线图,这里我们使用的汇总方法是序列方法 value_counts,该方法可以直接返回序列中各个唯一值的出现次数,调用方式为:Series.value_counts(normalize=False, sort=True, ascending=False, bins=None, dropna=True)

参数说明:

normalize:取值类型为布尔型,默认取值是 False,取值为 True 时将返回出现的频率

sort:取值类型为布尔型,默认取值是 True,即按照取值大小排序

ascending:取值类型为布尔型,表示是否按照升序排列,默认取值是 False,即降序

bins:只适用于取值类型为数值型的序列,用于将序列值划分到指定跨度的半开区间中,而不是进行计数

dropna:取值类型为布尔型,表示是否忽略缺失值,默认取值为 True

下面对序列"time"直接调用方法 value_counts,统计不同时点的评论数量并绘制折线图:


In [14]:df_reviews["time"].value_counts()
Out[14]:2014-12-11    99
        2015-07-01    93
        2015-07-02    58
                      ..
        2014-11-06     2
        2014-12-05     2
        2015-02-18     1
        Name: time, dtype: int64
In [15]:df_reviews["time"].value_counts().plot(kind='line', rot=0, figsize=(14, 8))
Out[15]:<matplotlib.axes._subplots.AxesSubplot at 0x7fd042724310>
@todo 补充截图 9.3.2.1

从趋势图可以看到,在 2015 年 1 月和 7 月均有明显的评论量增长。

8.3.2.2 分组趋势图

除了直接对时间数据进行统计汇总外,还可以以时间数据作为分组依据,对其他变量进行汇总,利用数据框的 groupby 方法即可轻松实现分组,最简单的调用方式如下:DataFrame.groupby(by=None, sort=True)

参数说明:

by:分组依据,取值类型可以为函数列表、字典、序列,或者数据框列名构成的列表或元组,将按照传入的参数进行分组。如果传入的是字典或序列,将以字典或序列的值作为分组依据。

sort:对分组的键值进行排序,但不影响组内取值的排序,默认取值为 True

该方法返回一个 GroupBy 对象,该对象本身并不包含实际的数据分组结果,只有对该对象调用相关方法时,pandas 才会根据 GroupBy 对象记录的信息进行分块运算,并返回计算结果。

常用的 GroupBy 对象方法有:

@todo 插入方法列表

下面以 kindle 评论文本的发布时间为分组依据,计算不同时间点的平均星级:


In [16]:group_time = df_reviews.groupby(["time"])
        group_time.mean().head()
Out[16]:@todo 补充截图 9.3.2.2-1

若只要看某列,可以通过索引实现:


In [17]:group_time["rating"].mean().head()
Out[17]:time  
        2014-10-03    4.645161  
        2014-10-04    4.909091  
        2014-10-05    4.666667  
        2014-10-06    4.800000  
        2014-10-07    4.421053  
        Name: rating, dtype: float64

或者直接对"rating"列进行分组:


In [18]:df_reviews["rating"].groupby(df_reviews["time"]).mean()
Out[18]:time
        2014-10-03    4.645161
        2014-10-04    4.909091
        2014-10-05    4.666667
                        ...   
        2015-08-22    4.230769
        2015-08-23    4.645161
        2015-08-24    4.400000
        Name: rating, dtype: float64

对得到的分组统计结果直接绘制折线图,即可得到评论评分序列的平均趋势图:


In [19]:df_reviews["rating"].groupby(df_reviews["time"]).mean().plot(kind='line', rot=0, figsize=(14, 8))
Out[19]:<matplotlib.axes._subplots.AxesSubplot at 0x7fd042c1aa10>
@todo 补充截图 9.3.2.2-2

从平均星级随时间的变动趋势图可以看出,整体星级保持在 4.3 分上下波动,在 2015 年 6月到 7 月之间出现了历史最低值 2.5 分。

统计不同时间热门词汇“闪屏”出现的次数,并绘制折线图:


In [20]:group_word = df_reviews.groupby(["time"])["word_count"].sum()
        group_word.plot(kind='line',figsize=(14, 8))
Out[20]:<matplotlib.axes._subplots.AxesSubplot at 0x7fd0423068d0>
@todo 补充截图 9.3.2.2-3

可以看出,2015 年 3 月以后,“闪屏”一次出现的次数明显增多。

results matching ""

    No results matching ""