[译]matplotlib可视化教程 :绘制有关Turmp, Clinton 和Sanders的推特信息

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[译]matplotlib可视化教程 :绘制有关Turmp, Clinton 和Sanders的推特信息相关的知识,希望对你有一定的参考价值。

使用 pandas 和 matplotlib 分析推特

Python有着各种各样的可视化库,其中包括了seaborn, networkxvispy。大部分的可视化Python库都是基于或部分基于matplotlib, matplotlib往往是绘制一些简单图的首选,但是同时对于太过复杂的图往往无能为力而不得不借助于其他库。

在本篇的matplotlib教程中,我们将会涉及到该库的基础,并通过一些中等难度的可视化示例进行阐释。

我们所使用的数据集为大概240,000条推特,这些推特的内容都有关于目前的美国总统候选人,也即Hillary Clinton, Donald Trump 和 Bernie Sanders。

包含全部 240,000 条推特的csv数据文件可在这里下载,如果你想爬取更多数据,可以再这里查找爬虫代码.

使用pandas探索推特

在开始绘图之前,我们先载入数据并做一些简单的探索。可以使用一个数据分析的Python库 pandas来帮助我们做这些。

先看一下当前工作目录,把下载的数据集 ,把下载的数据集 tweets.csv 放到该目录下即可。比如我的当前目录为/Users/xuliucheng, tweets.csv应该放到/Users/xuliucheng/tweets.csv

import os
print(os.getcwd())

准备好数据集后开始导入数据。在下面的代码,我们将会:

  • 导入pandas库
  • 将tweets.csv读取到pandas DataFrame
  • 打印DataFrame的前5行
# 导入pandas库
import pandas as pd

# 将tweets.csv读取到pandas DataFrame
tweets = pd.read_csv("tweets.csv")

# 打印DataFrame的前5行
tweets.head()
id id_str user_location user_bg_color retweet_count user_name polarity created geo user_description user_created user_followers coordinates subjectivity text
0 1 729828033092149248 Wheeling WV 022330 0 Jaybo26003 0.00 2016-05-10T00:18:57 NaN NaN 2011-11-17T02:45:42 39 NaN 0.0 Make a difference vote! WV Bernie Sanders Coul…
1 2 729828033092161537 NaN C0DEED 0 brittttany_ns 0.15 2016-05-10T00:18:57 NaN 18 // PSJAN 2012-12-24T17:33:12 1175 NaN 0.1 RT @HlPHOPNEWS: T.I. says if Donald Trump wins…
2 3 729828033566224384 NaN C0DEED 0 JeffriesLori 0.00 2016-05-10T00:18:57 NaN NaN 2012-10-11T14:29:59 42 NaN 0.0 You have no one to blame but yourselves if Tru…
3 4 729828033893302272 global C0DEED 0 WhorunsGOVs 0.00 2016-05-10T00:18:57 NaN Get Latest Global Political news as they unfold 2014-02-16T07:34:24 290 NaN 0.0 ‘Ruin the rest of their lives’: Donald Trump c…
4 5 729828034178482177 California, USA 131516 0 BJCG0830 0.00 2016-05-10T00:18:57 NaN Queer Latino invoking his 1st amendment privil… 2009-03-21T01:43:26 354 NaN 0.0 RT @elianayjohnson: Per source, GOP megadonor …

这里是对数据集中一些重要列的简要解释:

  • id : 数据库的行id(并不重要)
  • id_str : 当前tweet在Twitter网站的id
  • user_location : 在Twitter bio中发推人指定的地点
  • user_bg_color : 发推人profile的背景色
  • user_name : 发推人的Twitter用户名
  • polarity : 推特的情感指向,从-1到1,1代表非常积极,-1代表非常消极
  • created : 何时推特被发送
  • user_description : 发推人在个人档案中的自我简介
  • user_created : 发推人创建账户的时间
  • user_follower : 发推人拥有的粉丝数
  • text : 推特文本内容
  • subjectivity : 推特的主观性,0代表objective,1代表subjective

生成candidate列

对于这个数据集我们所能做的一些有趣的事情大多会涉及到关于不同候选者之间tweet的相互比较。 比如, 我们可以比较关于Donald Trump的推特其客观性怎么样,关于Bernie Sanders的推特其客观性又如何。

为此,我们首先需要生成一列数据来告诉我们在每条推特中都提及了哪些候选者。在下面的代码,我们将会:

  • 创建一个函数来找到在一段文本中出现了哪些候选者的名字
  • 使用DateFrame的apply方法生成一个candidate的新列,其中包含了每条推特所提及的候选者的名字
# 创建一个函数来找到在一段文本中出现了哪些候选者的名字
def get_candidate(row):
    candidates = []
    text = row["text"].lower()
    if "clinton" in text or "hillary" in text:
        candidates.append("clinton")
    if "trump" in text or "donald" in text:
        candidates.append("trump")
    if "sanders" in text or "bernie" in text:
        candidates.append("sanders")
    return ",".join(candidates)

# 使用DateFrame的apply方法生成一个candidate的新列,其中包含了每条推特所提及的候选者的名字
tweets["candidate"] = tweets.apply(get_candidate,axis=1)

绘制第一幅图

现在我们已经完成了使用matplotlib绘制第一幅图的一些准备工作。在matplotlib中,绘制一幅图像主要涉及到:

  • 创建一个Figure
  • 创建一个或多个绘制图像的Axes对象
  • 将所绘制的figure连同里面的plot显示为image

鉴于其灵活的机构, 你可以在matplotlib将多个plot绘制到一个单独的image中。每个Axes对象代表了一个单独的plot, 比如一个bar plot或histogram。

这听起来似乎有点复杂,但是matplotlib对于创建 Figure 与 Axes 提供了一些方便的途径。

导入matplotlib

为了能够使用matplotlib, 您首先需要使用 import matplotlib.pyplot as plt 导入该库。如果使用Jupyter notebook, 您可以使用 %matplotlib inline 使得matplotlib能够在notebook内运行。

import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

之所以导入 matplotlib.pyplot 是因为它包含了matplotlib的绘制函数, 而为了使用时更方便将其重命名为 plt .

绘制一个bar plot

一旦导入了matplotlib, 我们就能够对有多少tweet提及了每个候选者制作一个bar plot. 为此,我们将会:

  • 使用pandas Seriesvalue_counts来计算有多少tweet提及了每个候选者。
  • 使用plt.bar 来创建一个bar plot.
  • 显示计算结果
counts = tweets["candidate"].value_counts()
plt.bar(range(len(counts)), counts)
plt.show()

print(counts)

技术分享

trump                    119998
clinton,trump             30521
                          25429
sanders                   25351
clinton                   22746
clinton,sanders            6044
clinton,trump,sanders      4219
trump,sanders              3172
Name: candidate, dtype: int64

令人惊奇的是有关于Trump的tweet明显多于Sandars或Clinton!

您也许注意到我们没有显式创建一个Figure或任何的Axes对象,这是因为调用plt.bar会自动生成一个Figure和一个单独的Axes对象来表示bar plot.调用plt.show方法将会显式当前Figure中的一切内容。在当前情况下,它显示包含了bar plot的image。

matplotlib在pyplot模块有一些方法更快更方便的方式来创建一些常见类型的plot,它们将会自动创建一个Figure和一个Axes对象。如下是几种常见的方法:

调用这些方法将会自动创建Figure和Axes对象进行绘制。这些方法可以传入不同的参数来绘制不同的图像结果。

个性化绘制

现在我们已经制作了第一个基本的图像,接下来我们将继续绘制一个稍微个性化一点的图像。我们将制作一个直方图(histogram),然后为其添加标签以及一些其他信息。

在下面的代码,我们将会:

  • createduser_created列转化为pandas datetime 类型
  • 创建一个user_age列来显示账户创建以来的时间
  • 创建用户年龄的histogram
  • 显示图像
from datetime import datetime

tweets["created"] = pd.to_datetime(tweets["created"])
tweets["user_created"] = pd.to_datetime(tweets["user_created"])

tweets["user_age"] = tweets["user_created"].apply(lambda x : (datetime.now() - x).total_seconds()/3600/24/365 )
plt.hist(tweets["user_age"])

plt.show()

技术分享

添加label

我们可以在matplotlib plot中加入标题(title)或坐标轴标签(axis label)。

由于我们之前所讨论的所有方法,比如 barhist , 会自动在figure内部创建一个Figure或Axes对象,当上面的方法被调用时这些标签便会被加到Axes对象上。

我们可以使用上述方法给之前的直方图加上一些标签。在下面的代码,我们将会:

  • 生成一个与之前一样的直方图
  • 为直方图绘制一个标题
  • 为直方图绘制x轴标签
  • 为直方图绘制y轴标签
  • 显示plot
plt.hist(tweets["user_age"])
plt.title("Tweets mentioning candidates")
plt.xlabel("Twitter account age in years")
plt.ylabel("# of tweets")

plt.show()

技术分享

制作一个堆叠的直方图

目前的直方图的确能够显示出所有发推者的年龄,但是它并没有根据候选者进行隔断,而这可能会更有趣。我们可以在hist方法中利用额外选项来创建一个stacked histogram.

在下面的代码,我们将会:

  • 生成3个 pandas series, 每个仅包含某一指定候选者的tweet user_age数据
  • 通过调用带有额外选项的hist函数绘制一个stacked histogram
    • 指定一个列表作为输入
    • 指定stacked=True将会堆叠3个条状
    • 添加label选项将会为图例生成合适的标签
  • 调用plt.legend 方法将会在右上角绘制一个图例
  • 添加一个标题,x轴与y轴标签
  • 显示plot
cl_tweets = tweets["user_age"][tweets["candidate"] == "clinton"]
sa_tweets = tweets["user_age"][tweets["candidate"] == "sanders"]
tr_tweets = tweets["user_age"][tweets["candidate"] == "trump"]

plt.hist([cl_tweets,sa_tweets,tr_tweets], 
         stacked=True,
         label=["clinton","sanders","trump"]
        )

plt.legend()
plt.title("Tweets mentioning each candidate")
plt.xlabel("Twitter account age in years")
plt.ylabel("# of tweets")

plt.show()

技术分享

为直方图添加注释

我们可以利用matplotlib的长处在plot上绘制一些文本来添加注释。注释指向图表的一个指定部分,并且允许我们添加一个简短的描述片段。

在下面的代码,将会绘制一个与之前一样的直方图,不过我们将会调用plt.annnotate方法来添加一个注释到plot中。

plt.hist([cl_tweets,sa_tweets,tr_tweets],
         stacked=True,
         label=["clinton","sanders","trump"])

plt.legend()
plt.title("Tweets mentioning each candidate")
plt.xlabel("Twitter account age in years")
plt.ylabel("# of tweets")
plt.annotate(‘More Trump tweets‘, 
            xy=(1,35000),
            xytext=(2,35000),
            arrowprops=dict(facecolor=‘black‘))

plt.show()

技术分享

这里是传入annotate方法参数的简要介绍:

  • xy : 决定箭头开始处的(x,y)坐标
  • xytext : 决定注释文本开始处的(x,y)坐标
  • arroeprops : 指定关于箭头的一些选项,比如颜色

如上图所示,关于Trump的tweet显然要比其他候选人多出许多,不过在不同账户年限间,这种现象似乎没什么不同。

多个子图

到目前为止,我们已经使用了像plt.barplt.hist这样的方法,它们自动创建了了一个Figure对象和一个Axes对象。不过,当我们想对plot有更多的控制能力,可以显式创建这些对象。我们想对plot有更多的控制能力的其中一种情况便是在同一个image中绘制多个plot。

我们可以通过调用plt.subplots来生成一个Figure和多个Axes。我们传入两个参数nrowsncols,这将定义在Figure中Axes对象的布局。比如,plt.subplots(nrows=2,ncols=2)将会生成 2*2 的 网格 Axes objects. plt.subplots(nrows=2,ncols=1) 将会生成一个2*1的网格Axes objects, 然后垂直地将两个Axes堆叠在一起。

每个Axes对象都支持来自pyplot的大部分方法。比如,Axes对象可以调用bar方法来生成一个条形图。

提取颜色

首先,我们将会生成两列,redblue,来显示在每个推特用户的profile background中每种颜色有多少,从0到1.

在下面的代码,我们将会:

  • 使用apply方法遍历每一行的user_bg_color列,并在其中提取有多少的red.
  • 使用apply方法遍历每一行的user_bg_color列,并在其中提取有多少的blue.
import matplotlib.colors as colors

tweets["red"] = tweets["user_bg_color"].apply(lambda x: colors.hex2color(‘#{0}‘.format(x))[0])
tweets["blue"] = tweets["user_bg_color"].apply(lambda x: colors.hex2color(‘#{0}‘.format(x))[2])

创建plot

每个直方图将会显示有多少的推特用户的profile background包含了red或blue。

在下面的代码,我们将会:

  • 使用subplots方法生成一个Figure和多个Axes, 这些Axes将会以数组的形式返回。
  • axes以2*2的numpy数组的形式返回。我们使用数组的flat属性来提取每个axes个体。于是我们会有四个axes对象。
  • 使用hist方法在第一个axes中绘制一个直方图
  • 使用set_title方法设置第一个axes的title为Red in all backgrounds. 同样的功能也可用plt.title()实现。
  • 使用hist方法在第二个axes中绘制一个直方图
  • 使用set_title方法设置第二个axes的title为Blue in all backgrounds. 同样的功能也可用plt.title()实现。
  • 调用plt.tight_layout方法来减少图表间的内边距以适应所以的元素。
  • 显示图像。
fig, axes = plt.subplots(nrows=2, ncols=2)
ax0, ax1, ax2, ax3 = axes.flat

ax0.hist(tweets["red"])
ax0.set_title(‘Red in backgrounds‘)

ax1.hist(tweets["red"][tweets["candidate"] == "trump"].values)
ax1.set_title(‘Red in Trump tweeters‘)

ax2.hist(tweets["blue"])
ax2.set_title(‘Blue in backgrounds‘)

ax3.hist(tweets["blue"][tweets["candidate"] == "trump"].values)
ax3.set_title(‘Blue in Trump tweeters‘)

plt.tight_layout()
plt.show()

技术分享

移除通用背景色

Twitter有默认的profile background color, 所以我们可能需要取出它们一遍能够减少噪声生成一个更准确的plot。以16进制形式,#000000表示黑色,#ffffff表示白色。

这里是如何找到背景色中的最常见颜色。

tweets["user_bg_color"].value_counts()
C0DEED    108977
000000     31119
F5F8FA     25597
131516      7731
1A1B1F      5059
022330      4300
0099B9      3958
642D8B      3767
FFFFFF      3101
9AE4E8      2651
ACDED6      2383
352726      2338
C6E2EE      1978
709397      1518
EBEBEB      1475
FF6699      1370
BADFCD      1336
FFF04D      1300
EDECE9      1225
B2DFDA      1218
DBE9ED      1113
ABB8C2      1101
8B542B      1073
3B94D9       623
89C9FA       414
DD2E44       351
94D487       318
4A913C       300
9266CC       287
F5ABB5       267
           ...  
5470A8         1
00AEFF         1
C49C4B         1
778877         1
09380E         1
09536E         1
3D3C3D         1
48394D         1
3D3C3A         1
140C0E         1
AE1BCF         1
EBE39B         1
056785         1
FCF3EA         1
2E332F         1
FCF7F8         1
FCF7F7         1
0F6B2C         1
1D1F1B         1
180018         1
2686B3         1
8F0E8F         1
CCD4E8         1
FFEF42         1
08F5F5         1
4E5254         1
42373E         1
272D29         1
F00CC2         1
A3004D         1
Name: user_bg_color, dtype: int64

现在,我们可以移除三种最常见的颜色,并仅绘制有着唯一背景色的用户。下面的代码基本就是我们之前所做的事情,但是我们将会:

  • user_bg_color中移除C0DEED,000000,F5F8FA
tc = tweets[~tweets["user_bg_color"].isin(["C0DEED","000000","F5F8FA"])]

def create_plot(data):
    fig, axes = plt.subplots(nrows=2, ncols=2)
    ax0, ax1, ax2, ax3 = axes.flat

    ax0.hist(data["red"])
    ax0.set_title(‘Red in backgrounds‘)

    ax1.hist(data["red"][data["candidate"] == "trump"].values)
    ax1.set_title(‘Red in Trump tweets‘)

    ax2.hist(data["blue"])
    ax2.set_title(‘Blue in backgrounds‘)

    ax3.hist(data["blue"][data["candidate"] == "trump"].values)
    ax3.set_title(‘Blue in Trump tweeters‘)

    plt.tight_layout()
    plt.show()

create_plot(tc)

技术分享

如图所示,对于那些发推内容关于Trump的用户,其红蓝背景色分布与所有用户的红蓝背景色分布大致相同。

Plotting sentiment

我们可以使用TextBlob对每条tweet生成一个情感得分,并存储在polarity列。 我们可以为每个候选人绘制平均值和标准差。标准差将会告诉我们在所有的tweet间其变化偏差有多大,而平均值将会告诉我们tweet的平均值是多少。

为此,我们可以将2个Axes添加到一个Figure,在其中一个绘制polarity的平均值,另一个绘制标准差。因为在这些plot里有很多文本标记,所以我们需要增大生成的figure的size来进行匹配。可以通过plt.subplots方法的figsize选项来实现。

下面的代码将会:

  • 根据candidate对tweet进行聚合,计算每个数值列的平均值与标准差(包括polarity
  • 创建一个7*7 inches的Figure,带有2个Axes对象,垂直排列
  • 第一个Axes对象绘制关于标准差的一个bar plot
    • 使用set_xticklabels设置tick label, 并使用rotate参数将标签旋转45
    • 设置标题
  • 将上一步操作同样应用到第二个Axes对象
  • 显示图像
gr = tweets.groupby("candidate").agg([np.mean, np.std])

fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(7,7))
ax0, ax1 = axes.flat

std = gr["polarity"]["std"].iloc[1:]
mean = gr["polarity"]["mean"].iloc[1:]
ax0.bar(range(len(std)), std)
ax0.set_xticklabels(std.index, rotation=45)
ax0.set_title(‘Standard deviation of tweet sentiment‘)

ax1.bar(range(len(mean)), mean)
ax1.set_xticklabels(mean.index, rotation=45)
ax1.set_title(‘Mean tweet sentiment‘)

plt.tight_layout()
plt.show()

技术分享

Generating a side by side bar plot

我们可以根据candidate绘制关于tweet长度的bar plot. 首先,我们将tweet分割为short,mediumlong三类。然后,我们计算关于candidate的每类tweet的数量并为之生成一个bar plot。

Generating tweet lengths

为了绘制tweet的长度,我们首先必须对tweet进行分类,然后计算出每类tweet的数量。

在下面的代码,我们将会:

  • 定义一个函数对tweet进行标记,tweet少于100个字符标记为short, 100135个字符标记为medium,超过135个字符标记为long
  • 使用apply生成新列tweet_length
  • 根据每个candidate计算每类有多少tweet
def tweet_lengths(text):
    if len(text) < 100:
        return "short"
    elif len(text) <= 135:
        return "medium"
    else:
        return "long"
tweets["tweet_length"] = tweets["text"].apply(tweet_lengths)

tl = {}
for candidate in ["clinton", "sanders", "trump"]:
    tl[candidate] = tweets["tweet_length"][tweets["candidate"] == candidate].value_counts()

Plotting

fig, ax = plt.subplots()
width = .5
x = np.array(range(0, 6, 2))
ax.bar(x, tl["clinton"], width, color=‘g‘)
ax.bar(x+width, tl["sanders"], width, color=‘b‘)
ax.bar(x+(width*2), tl["trump"], width, color=‘r‘)

ax.set_ylabel(‘## of tweets‘)
ax.set_title(‘Number of Tweets per candidate by length‘)
ax.set_xticks(x+(width*1.5))
ax.set_xticklabels((‘long‘, ‘medium‘, ‘short‘))
ax.set_xlabel(‘Tweet length‘)

plt.show()

技术分享

Next steps

至此我们对于matplotlib如何绘制图像与数据集已经有了一定了解,如果您想了解更多的matplotlib内部如何运作,可以阅读这里.

接下来,您可以:

  • 分析用户的描述信息,看一下关于候选者的描述信息的长度如何变化
  • 探索时间信息 – 候选人的支持者是否偏向于某些特定的时间发推?
  • 探索用户地点,看一下哪位candidate的支持者在哪些州最多
  • 看一下是否用户名称的类型是否会偏向于发推于某些类型的candidate
    • 是否用户名称的长度与对候选人的支持有些相关性?
    • 哪位候选人拥有最多的caps supporter
  • 抓取更多数据,看模式是否会有所变化

注:




以上是关于[译]matplotlib可视化教程 :绘制有关Turmp, Clinton 和Sanders的推特信息的主要内容,如果未能解决你的问题,请参考以下文章

Matplotlib:plotting(译)

地铁译:Spark for python developers ---Spark处理后的数据可视化

Matplotlib path 教程

Python可视化|Matplotlib39-Matplotlib 1.4W+字教程(珍藏版)

10分钟入门Matplotlib: 数据可视化介绍&使用教程

Matplotlib基础教程之折线图