AIPyTorch程序员

使用python机器学习(四)

2017-07-12  本文已影响1565人  jacksu在简书

前面三篇文章《使用python机器学习(一)》、《使用python机器学习(二)》《使用python机器学习(三)》分别介绍了numpy、scipy、pandas的简单使用。
学习matplotlib时,找到了使用Pandas和Matplotlib分析Tweets这篇文章,在此对其转载,欢迎大家学习。文中涉及代码
github路径在此

Python有多种可视化库,包括seaborn, networkx, 和vispy。大多数的Python可视化库全部或部分基于matplotlib,这往往是绘制简单的图的第一种手段,也是绘制那些难以在其他库绘制的图的最后一种手段。

在这个matplotlib教程中,我们将介绍该库的基本知识,并看看如何进行一些中间可视化。

我们将使用包含将近240,000条关于Hillary Clinton, Donald Trump, 和Bernie Sanders,目前所有美国总统候选人的推特的数据集。

该数据是从Twitter Streaming API拉过来的,而所有240,000条推特的csv文件可以在这里下载。如果你想自己爬取更多数据,那么你可以看看这里的爬虫代码。

使用Pandas探索Tweets

在我们开始绘制之前,让我们加载数据并进行一些探索。我们可以使用Pandas,这个数据分析Python库,来帮助我们。在下面的代码中,我们将:


    import pandas as pd
    
    tweets = pd.read_csv("tweets.csv")
    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 ...

下面是该数据中重要列的简要说明:

生成候选人列

我们可以用这个数据集进行的最有趣的事情包括,比较关于一个候选人的推特和另一个候选人的推特。例如,我们可以比较关于Donald Trump的推特的客观性和关于Bernie Sanders的推特的客观性。

为了完成这个任务,我们首先需要生成一个列,该列表示每条推特提到了哪个候选人。在下面的代码中,我们将:


    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)
    
    tweets["candidate"] = tweets.apply(get_candidate,axis=1)

绘制第一张图

现在,我们准备好了。我们已经准备好使用matplotlib绘制第一张图。在matplotlib中,绘制一张图包括:

由于其灵活性,你可以在matplotlib中把多个图绘制在一张图片中。每一个Axes对象表示一张图,例如一个柱状图或直方图。

这可能听起来很复杂,但是matplotlib具有一些方便的方法,可以为我们完成建立一个Figure和Axes对象的工作。

导入matplotlib

为了使用matplotlib,首先,你讲需要使用import matplotlib.pyplot as plt导入该库。如果你正使用Jupyter notebook,从而在该notebook内部设置使用matplotlib。


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

我们导入matplotlib.pyplot,因为这包含matplotlib的绘图函数。为了方便,我们重命名它为plt,因此可以更快绘图。

绘制柱状图

一旦我们导入了matplotlib,我们就可以绘制一张关于每个候选人被提到的推特数的柱状图。为了完成这点,我们将:


    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的推特比关于Sanders或者Clinton的推特多得惊人!

你可能注意到,我们并没有创建Figure或者任何Axes对象。这是因为调用plt.bar会自动设置一个Figure和一个Axes对象,表示该柱状图。调用plt.show方法会显示当前图表中的任何东西。在这种情况下,它显示一个包含了一个柱状图的图像。

pyplot模块中,matplotlib有一些方法可以使得创建常见类型的图更快和更方便,因为它们自动创建一个Figure和一个Axes对象。最广泛使用的是:

调用任意这些方法将自动设置Figure和Axes对象,并且绘制图。这些方法的每一个都有不同的参数,可以传递它们来修改效果图。

自定义图

现在,我们已经有了第一个基本的图,可以继续创建第二个更个性化的图了。我们会绘制一张基本的直方图,然后修改它,以添加标签及其他信息。

我们可以看的事情之一就是发推特的用户账号年龄。我们可以找到发关于Trump的推特的用户账号和发关于Clinton的推特的用户账号的创建时间之间是否有区别。拥有更多最近创建的用户账号的候选人可能意味着使用假账号进行某种Twitter操纵。

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


    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()

添加标签

我们可以添加标题和轴标签到matplotlib图中。完成这件事的通用方法是:

由于我们之前讨论到的所有方法,像barhist,都会在figure中自动创建一个Figure和一个Axes对象,因此当调用该方法时,这些标签将会被添加到Axes对象上。

我们可以用上面的方法添加标签到我们之前的直方图上。在下面的代码中,我们会:


    plt.hist(tweets["user_age"])
    plt.title("Tweets mentioning candidates")
    plt.xlabel("Twitter account age in years")
    plt.ylabel("# of tweets")
    plt.show()

绘制叠加柱状图

现在的直方图可以很好的告诉我们所有的推特账户的注册年龄,但是它并没有根据候选人进行分类,这可能会更有趣。我们可以在hist放中添加额外的选项,以创建一个叠加柱状图。

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


    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()

注释直方图

我们可以利用matplotlibs在图上绘制文本的能力来添加注释。注释指向图表的特定部分,让我们一个片段来描述一些东东。

在下面的代码中,我们会创建和上面一样的直方图,但是会调用plt.annotate方法来添加注释到图中。


    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的选项的行为描述:

正如你所见的,关于Trump的推特明显比其他候选人更多,但是在账号注册年龄上,看不出显著的差异。

多个子图

目前为止,我们使用了一些方法,像plt.barplt.hist,它们会自动创建一个Figure对象和一个Axes对象。然而,当我们想获得关于图的更多控制时,我们可以显式创建这些对象。我们可能想要更多控制的场景之一是,当我们想要在同张图上并排放置多个图表。

通过调用plt.subplots方法,我们可以生成一个Figure和多个Axes对象。传递两个参数,nrowsncols,它们定义在Figure中Axes对象的布局。例如,plt.subplots(nrows=2, ncols=2)会生成2x2网格的Axes对象。plt.subplots(nrows=2, ncols=1)会生成2x1网格的Axes对象,然后将这两个Axes对象垂直堆积在一起。

每个Axes对象支持pyplot中的大多数方法。例如,我们可以在一个Axes对象上调用bar方法来生成一个柱状图。

提取颜色

我们将生成4张图,用来那些发关于Trump推特的用户的Twitter背景色中的红色和蓝色的数量。这可能显示,确定为共和党派的推特用户是否更倾向于在他们的个人资料中使用红色。

首先,我们要生成两列,redblue,用来表示在每个推特用户的个人资料背景中,每种颜色的多少,从01

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


    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])

创建图

一旦我们拥有了数据,我们就可以创建图。每张图将会是一个直方图,用以显示个人资料背景包含特定数量的蓝色或红色的推特用户数。

在下面的代码中,我们:


    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有默认的个人资料背景颜色,我们或许应该移除它,这样才能通过消除噪音,以生成一个更准确的图。该演示是十六进制格式的,其中,#000000是黑色,而#ffffff是白色。

下面是如何查找背景颜色中的最常见的颜色:


    tweets["user_bg_color"].value_counts()

        C0DEED    108977
        000000     31119
        F5F8FA     25597
        131516      7731
        1A1B1F      5059
        022330      4300
        0099B9      3958
    

现在,我们可以删除三种最常见的颜色,然后只画出那些有唯一背景颜色的用户。下面的代码大多数我们之前做过的,但是我们会:


    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的推特的用户的背景颜色中,红色和蓝色的分布几乎与所有推特用户的分布相同。

绘制情绪

我们使用TextBlob,为每条推特生成情绪分值,存储在polarity列中。我们可以为每个候选人绘制平均值以及标准偏差。标准偏差将会告诉我们在所有的推特之间,变化有多宽,而平均值将会告诉我们平均推特是什么样子的。

要这样做,我们可以添加2个Axes到单个Figure上,然后在一个中绘制polarity平均值,在另一个中绘制标准偏差。由于在这些图中,有大量的文本标签,因此我们将需要增加生成的图像的大小来匹配。我们可以使用plt.subplots方法中的figsize选项来做到这点。

下面的代码将会:


    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()

生成并排条形图

我们可以使用柱状图绘制根据候选人分组的推特长度。首先将推特分成short, medium, 和long推特。然后计算提到每个候选人的推特落到每个组的个数。接着,生成并排每个候选人的条的柱状图。

生成tweet长度

要绘制推特长度,我们首先必须对这些推特进行分类,然后找出关于每个候选人的推特落入到每个箱中的个数。

下面的代码中,我们将:


    def tweet_lengths(text):
        if len(text) < 100:
            return "short"
        elif 100 <= 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()

绘图

现在,我们有了想要绘制的数据了,可以生成并排柱状图了。我们将使用bar方法来在相同的轴上,为每个候选人绘制推特长度。然而,我们将使用一个偏移量来将所绘制的第二个和第三个候选人的条向右偏移。这将为我们提供三个分类区域,short, medium, 和long,每个区域中,每个候选人有一个条。

下面的代码中,我们:


    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()

下一步

我们已经学到了很多关于matplotlib生成图的知识,以及仔细好好看了该数据集。如果你想要阅读更多关于matplotlib内部如何绘制的内容,阅读这里

接下来,你可以绘制很多的图:

希望这个matplotlib教程有用,如果你对这个数据做了任何好玩的分析,在下面(Ele注:去原文哈)留言吧 —— 我们很想知道!

上一篇下一篇

猜你喜欢

热点阅读