前面三篇文章《使用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庫,來幫助我們。在下面的代碼中,我們將:
- 導入Pandas庫。
- 讀取
tweets.csv
到一個Pandas DataFrame種。 - 打印出該DataFrame的前
5
行。
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 ...
下面是該數據中重要列的簡要說明:
-
id
– 在數據庫中行的id(這并不重要)。 -
id_str
– Twitter上推特的id。 -
user_location
– 推特用戶在他們的Twitter信息中指定的位置。 -
user_bg_color
– 推特用戶簡介的背景色。 -
user_name
– 推特用戶的Twitter用戶名。 -
polarity
– 推特的情感,從-1
到1
。1
表示非常積極,-1
表示非常消極。 -
created
– 推特發送時間 -
user_description
– 推特用戶在其簡介中指定的描述。 -
user_created
– 推特賬號創建時間。 -
user_follower
– 該推特的關注人數。 -
text
– 推特的文本。 -
subjectivity
– 推特的主觀性和客觀性。0
表示非常可觀,1
表示非常主觀。
生成候選人列
我們可以用這個數據集進行的最有趣的事情包括,比較關于一個候選人的推特和另一個候選人的推特。例如,我們可以比較關于Donald Trump的推特的客觀性和關于Bernie Sanders的推特的客觀性。
為了完成這個任務,我們首先需要生成一個列,該列表示每條推特提到了哪個候選人。在下面的代碼中,我們將:
- 創建一個函數,查找在一段文字中,哪個候選人的名字出現了。
- 在DataFrames之上使用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)
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,我們就可以繪制一張關于每個候選人被提到的推特數的柱狀圖。為了完成這點,我們將:
- 使用Pandas Series上的value_counts函數來統計每個候選人有多少條提及他的推特。
- 使用
plt.bar
來創建一個柱狀圖。我們將傳遞取值從0
到candidate
列的唯一值數目的數字列表,作為x軸輸入,把計數當成y軸輸入。 - 顯示計數,從而我們擁有更多關于每一個柱子表示什么的上下文信息。
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對象。最廣泛使用的是:
- plt.bar – 創建一個柱狀圖。
- plt.boxplot – 創建一個盒形圖和須狀圖。
- plt.hist – 創建一個直方圖。
- plt.plot – 創建一個線條圖。
- plt.scatter – 創建一個散點圖。
調用任意這些方法將自動設置Figure和Axes對象,并且繪制圖。這些方法的每一個都有不同的參數,可以傳遞它們來修改效果圖。
自定義圖
現在,我們已經有了第一個基本的圖,可以繼續創建第二個更個性化的圖了。我們會繪制一張基本的直方圖,然后修改它,以添加標簽及其他信息。
我們可以看的事情之一就是發推特的用戶賬號年齡。我們可以找到發關于Trump的推特的用戶賬號和發關于Clinton的推特的用戶賬號的創建時間之間是否有區別。擁有更多最近創建的用戶賬號的候選人可能意味著使用假賬號進行某種Twitter操縱。
在下面的代碼中,我們會:
- 將
created
和user_created
列轉換成Pandas datetime類型。 - 創建一個
user_age
列,表示從該賬號創建后至今的天數。 - 創建用戶年齡直方圖。
- 顯示該直方圖。
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圖中。完成這件事的通用方法是:
- plt.title – 添加標題到圖上。
- plt.xlabel – 添加x軸標簽。
- plt.ylabel – 添加y軸標簽。
由于我們之前討論到的所有方法,像bar
和hist
,都會在figure中自動創建一個Figure和一個Axes對象,因此當調用該方法時,這些標簽將會被添加到Axes對象上。
我們可以用上面的方法添加標簽到我們之前的直方圖上。在下面的代碼中,我們會:
- 生成我們之前完成的相同的直方圖。
- 畫一個標題到該直方圖。
- 畫一個x軸標簽到該直方圖上。
- 畫一個y軸標簽到該直方圖上。
- 顯示該圖。
plt.hist(tweets["user_age"])
plt.title("Tweets mentioning candidates")
plt.xlabel("Twitter account age in years")
plt.ylabel("# of tweets")
plt.show()
繪制疊加柱狀圖
現在的直方圖可以很好的告訴我們所有的推特賬戶的注冊年齡,但是它并沒有根據候選人進行分類,這可能會更有趣。我們可以在hist
放中添加額外的選項,以創建一個疊加柱狀圖。
在下面的代碼中,我們會:
- 生成三個Pandas series,每個只包含關于某個特定的候選人的推特的
user_age
數據。 - 通過調用
hist
方法,并添加額外的選項創建一個疊加直方圖。- 指定一個列表作為輸入將繪制三組柱狀圖。
- 指定
stacked=True
將疊加這三個條的集合。 - 增加
label
選項將為圖例生成正確的標簽。
- 調用plt.legend方法來在右上角繪制一個圖例。
- 添加標題,x軸和y軸標簽。
- 顯示該圖。
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
的選項的行為描述:
-
xy
– 確定x
和y
坐標中箭頭應該從哪里開始。 -
xytext
– 確定x
和y
坐標中文本應該從哪里開始。 -
arrowprops
– 指定箭頭相關的選項,例如顏色。
正如你所見的,關于Trump的推特明顯比其他候選人更多,但是在賬號注冊年齡上,看不出顯著的差異。
多個子圖
目前為止,我們使用了一些方法,像plt.bar
和plt.hist
,它們會自動創建一個Figure對象和一個Axes對象。然而,當我們想獲得關于圖的更多控制時,我們可以顯式創建這些對象。我們可能想要更多控制的場景之一是,當我們想要在同張圖上并排放置多個圖表。
通過調用plt.subplots方法,我們可以生成一個Figure和多個Axes對象。傳遞兩個參數,nrows
和ncols
,它們定義在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背景色中的紅色和藍色的數量。這可能顯示,確定為共和黨派的推特用戶是否更傾向于在他們的個人資料中使用紅色。
首先,我們要生成兩列,red
和blue
,用來表示在每個推特用戶的個人資料背景中,每種顏色的多少,從0
到1
。
在下面的代碼中,我們將:
- 使用
apply
方法來遍歷user_bg_color
列中的每一行,然后提取其中的紅色總數。 - 使用
apply
方法來遍歷user_bg_color
列中的每一行,然后提取其中的藍色總數。
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])
創建圖
一旦我們擁有了數據,我們就可以創建圖。每張圖將會是一個直方圖,用以顯示個人資料背景包含特定數量的藍色或紅色的推特用戶數。
在下面的代碼中,我們:
- 使用
subplots
方法生成一個Figure和多個Axes。Axes將作為數組返回。 - Axes在一個2x2 NumPy數組中返回。通過使用數組的flat屬性,提取每個Axes對象。這為我們提供了
4
個Axes對象用以工作。 - 使用hist方法在第一個Axes中繪制一個直方圖。
- 使用set_title方法,設置第一個Axes的標題為
Red in all backgrounds
。這與plt.title
功能一致。 - 使用hist方法在第二個Axes中繪制一個直方圖。
- 使用set_title方法,設置第二個Axes的標題為
Red in Trump tweeters
。 - 使用hist方法在第三個Axes中繪制一個直方圖。
- 使用set_title方法,設置第三個Axes的標題為
Blue in all backgrounds
。這與plt.title
功能一致。 - 使用hist方法在第四個Axes中繪制一個直方圖。
- 使用set_title方法,設置第四個Axes標題為
Blue in Trump tweeters
。 - 調用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有默認的個人資料背景顏色,我們或許應該移除它,這樣才能通過消除噪音,以生成一個更準確的圖。該演示是十六進制格式的,其中,#000000
是黑色,而#ffffff
是白色。
下面是如何查找背景顏色中的最常見的顏色:
tweets["user_bg_color"].value_counts()
C0DEED 108977
000000 31119
F5F8FA 25597
131516 7731
1A1B1F 5059
022330 4300
0099B9 3958
現在,我們可以刪除三種最常見的顏色,然后只畫出那些有唯一背景顏色的用戶。下面的代碼大多數我們之前做過的,但是我們會:
- 從
user_bg_color
中移除C0DEED
,000000
, 和F5F8FA
。 - 創建一個函數,不在最后一個圖表中繪制邏輯。
- 繪制和前面
4
個圖一樣的圖,除了user_bg_color
中最常見的顏色。
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
選項來做到這點。
下面的代碼將會:
- 根據候選人將推特進行分組,對于每個數值列(包括
polarity
),計算平均值和標準方差。 - 創建一個
7
x7
英寸的Figure,帶2個Axes對象,垂直排列。 - 在第一個Axes對象上創建標準偏差的柱狀圖。
- 使用set_xticklabels方法設置刻度標記,使用
rotation
參數旋轉標簽45
度。 - 設置標題。
- 使用set_xticklabels方法設置刻度標記,使用
- 在第二個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()
生成并排條形圖
我們可以使用柱狀圖繪制根據候選人分組的推特長度。首先將推特分成short
, medium
, 和long
推特。然后計算提到每個候選人的推特落到每個組的個數。接著,生成并排每個候選人的條的柱狀圖。
生成tweet長度
要繪制推特長度,我們首先必須對這些推特進行分類,然后找出關于每個候選人的推特落入到每個箱中的個數。
下面的代碼中,我們將:
- 定義一個函數,如果推特長度小于
100
個字符,將其標記為short
;如果在100
到135
個字符之間,將其標記為medium
;如果超過135
個字符,將其標記為long
。 - 使用
apply
來生成一個新的列tweet_length
。 - 找出關于每個候選人的推特落入到每個組中的個數。
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
,每個區域中,每個候選人有一個條。
下面的代碼中,我們:
- 創建一個Figure和一個Axes對象。
- 為每個條定義
width
,.5
。 - 生成值序列
x
,即0
,2
,4
。每個值是一個分類,例如short
,medium
, 和long
,的起始。我們設置每個分類之間的距離為2
,這樣多個條之間就有空間了。 - 在Axes對象上繪制
clinton
推特,條位于x
定義的位置上。 - 在Axes對象上繪制
sanders
推特,但是添加width
到x
上,使得條移動到右方。 - 在Axes對象上繪制
trump
推特,但是添加width * 2
到x
上,使得條移動到更右方。 - 設置軸標簽和標題。
- 使用
set_xticks
將刻度標記移動到每個分類區域的中心。 - 設置刻度標記。
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注:去原文哈)留言吧 —— 我們很想知道!