Python 數(shù)據(jù)可視化(3)

在數(shù)據(jù)分析中,數(shù)據(jù)可視化非常重要。我們可以將數(shù)據(jù)繪制成各種圖形,比如直方圖,散點(diǎn)圖等,從圖形中可以明顯看出各種數(shù)據(jù)特征。我們將學(xué)習(xí)各種圖形的用途,以及在 Python 中如何使用 matplotlib 以及其他工具繪制各種圖形。

知識(shí)點(diǎn)

  • matplotlib 繪圖;
  • 各種圖形的用途;

matplotlib

matplotlib 目前是 Python 中功能最強(qiáng)大的繪圖軟件包,在開(kāi)始其他內(nèi)容之前,先讓我們看下使用 matplotlib 生成散點(diǎn)圖的代碼:

import numpy as np
import matplotlib.pyplot as plt

N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2

plt.scatter(x, y, s=area, c=colors, alpha=0.5)
plt.show()
image.png

以上代碼中,我們將 matplotlib.pyplot 導(dǎo)入后命名為 plt, 在后面所有的課程內(nèi)容中,出現(xiàn)的 plt 都默認(rèn)是 matplotlib.pyplot 包。在代碼最后一行 plt.show() 執(zhí)行以后,將彈出一個(gè)窗口顯示繪制的圖形,這個(gè)時(shí)候 IPython 終端將不能輸入任何代碼,當(dāng)我們關(guān)閉圖形窗口以后,IPython 終端將恢復(fù)輸入模式。

matplotlib 基礎(chǔ)

matplotlib 是面向?qū)ο蟮睦L圖工具包,繪制的圖形中每一個(gè)元素都是一個(gè)對(duì)象,比如線條,文字,刻度等信息,可以通過(guò)修改這些對(duì)象的屬性,從而改變繪圖樣式。

matplotlib 中主要的繪圖對(duì)象列表如下:

  • Figure 對(duì)象,可以想象為一張畫(huà)布;
  • Axes 對(duì)象,字面理解為坐標(biāo)軸(因?yàn)槊恳粋€(gè) Axes 都有一套 X Y軸坐標(biāo)系,繪制圖形時(shí)基于此坐標(biāo)系繪制。) 也可以認(rèn)為是子圖,在一個(gè) Figure 對(duì)象中可以包含多個(gè) Axes 對(duì)象,也就是說(shuō)一張畫(huà)布可以包含多個(gè)子圖;
  • Line2D 對(duì)象,代表線條;
  • Text 對(duì)象,代表了文字,比如一張子圖需要標(biāo)題,就可以使用一個(gè) Text 對(duì)象;

雖然 matplotlib 是面向?qū)ο蟮睦L圖工具包,但是也提供了一些常用的繪圖方法,可以直接調(diào)用 plt 模塊相關(guān)方法就可以完成各種繪圖需求,這是因?yàn)?plt 模塊內(nèi)部保存了當(dāng)前的 Figure 對(duì)象信息,當(dāng)使用 plt 的相關(guān)方法繪圖時(shí),底層實(shí)際調(diào)用了當(dāng)前 Figure 對(duì)象的相關(guān)方法。在前面的散點(diǎn)圖例子中,我們沒(méi)有創(chuàng)建過(guò)任何 Figure 對(duì)象也成功的繪制出了圖形,這就是因?yàn)?plt 會(huì)默認(rèn)創(chuàng)建 Figure 對(duì)象,并將它保存在 plt 模塊內(nèi)部??梢酝ㄟ^(guò) plt.gcf() 和 plt.gca() 分別獲取當(dāng)前用于繪圖的 Figure 和 Axes 對(duì)象。

我們可以通過(guò) plt.figure() 創(chuàng)建一個(gè)新的 Figure 對(duì)象,然后在此 Figure 對(duì)象上創(chuàng)建 Axies 對(duì)象:

In [28]: fig1 = plt.figure()

In [29]: ax1 = fig1.add_subplot(1, 1, 1)

In [30]: fig1
Out[30]: <matplotlib.figure.Figure at 0x10e3a35f8>

In [31]: plt.gcf()
Out[31]: <matplotlib.figure.Figure at 0x10e3a35f8>

In [32]: ax1
Out[32]: <matplotlib.axes._subplots.AxesSubplot at 0x10e22f6d8>

In [33]: plt.gca()
Out[33]: <matplotlib.axes._subplots.AxesSubplot at 0x10e22f6d8>

In [34]: fig2 = plt.figure()

In [35]: ax2 = fig2.add_subplot(1, 1, 1)

In [36]: fig2
Out[36]: <matplotlib.figure.Figure at 0x10e415860>

In [37]: plt.gcf()
Out[37]: <matplotlib.figure.Figure at 0x10e415860>

以上代碼中,我們分別創(chuàng)建了 fig1 和 fig2 兩個(gè) Figure 對(duì)象,以及 ax1 和 ax2 兩個(gè) Axes 對(duì)象??梢钥吹?,每當(dāng)我們生成新的 Figure 對(duì)象時(shí),plt.gcf() 獲取到的當(dāng)前的 Figure 對(duì)象也變成了新創(chuàng)建的 Figure 對(duì)象,因?yàn)樗麄兊膬?nèi)存地址相同( at 字符后面是內(nèi)存地址)。 fig.add_subplot(1, 1, 1) 方法,用于在 Figure 對(duì)象上創(chuàng)建一個(gè)新 Axes 對(duì)象,由于 Figure 對(duì)象可以包含多個(gè) Axes 對(duì)象,所以這里的參數(shù)含義是說(shuō),添加一個(gè) Axes 對(duì)象到布局為一行一列的第一個(gè)位置上。當(dāng)然可以改變布局,比如 fig.add_subplot(2, 2, 1) 含義是添加一個(gè) Axes 對(duì)象到布局為兩行兩列的第一個(gè)位置上,也就是說(shuō)我們依次調(diào)用 fig.add_subplot(2, 2, 2), fig.add_subplot(2, 2, 3), fig.add_subplot(2, 2, 4) 在 Figure 對(duì)象上插入四個(gè) Axes 對(duì)象,布局為兩行兩列,如下代碼:

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure() #建立figure實(shí)例,可以想象成一張畫(huà)布

ax1 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2)
ax3 = fig.add_subplot(2,2,3)

ax1.plot(np.random.randn(50).cumsum(),'k--')
ax2.hist(np.random.randn(100),bins=20,color='k')
ax3.scatter(np.arange(30),np.arange(30)+3*np.random.randn(30))

plt.show()

以上代碼,首先創(chuàng)建了一個(gè) Figure 對(duì)象,然后接著插入了 3 個(gè) Axes 對(duì)象,接著分別在 Axes 對(duì)象上繪制了累積和線圖,直方圖以及散點(diǎn)圖,最后通過(guò) plt.show() 方法顯示出圖形如

image.png

常用屬性設(shè)置

matplotlib 繪制的圖形可以設(shè)置各種屬性,比如設(shè)置坐標(biāo)系的刻度,標(biāo)題,標(biāo)簽等屬性。下面我們將通過(guò)具體的例子演示。 matplotplib 繪制圖形時(shí),基于 X, Y 軸坐標(biāo)系繪圖。我們可以設(shè)置 X, Y 坐標(biāo)的各種屬性,比如刻度,范圍,標(biāo)簽等屬性,示例代碼如下:

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(1,1,1)

# 設(shè)置標(biāo)題
ax.set_title("Axes Example")

major_ticks = np.arange(0, 101, 20)
minor_ticks = np.arange(0, 101, 5)

# 設(shè)置刻度
ax.set_xticks(major_ticks)
ax.set_xticks(minor_ticks, minor=True)
ax.set_yticks(major_ticks)
ax.set_yticks(minor_ticks, minor=True)

# 設(shè)置 X, Y 軸 標(biāo)簽
ax.set_xlabel("X axis")
ax.set_ylabel("Y axis")

# 設(shè)置網(wǎng)格
ax.grid(which='minor', alpha=0.2)
ax.grid(which='major', alpha=0.5)

# 添加文字
ax.text(50, 50, "jianshu")

plt.show()

下面我們具體分析下以上代碼,首先創(chuàng)建了一個(gè) Figure 對(duì)象,接著在該 Figure 對(duì)象上創(chuàng)建了唯一一個(gè) Axes 對(duì)象,后續(xù)的所有屬性都基于該 Axes 對(duì)象設(shè)置:

  • ax.set_title 設(shè)置圖形的標(biāo)題;
  • ax.set_xticks 設(shè)置 X 軸的刻度,其中 minor=True 參數(shù)表示設(shè)置更小的刻度;
  • ax.set_yticks 設(shè)置 Y 軸的刻度;
  • ax.set_xlabel 設(shè)置 X 軸的標(biāo)簽;
  • ax.set_ylabel 設(shè)置 Y 軸的標(biāo)簽;
  • ax.grid 開(kāi)啟圖形的刻度網(wǎng)格,其中 minor=True 參數(shù)表示顯示小刻度的網(wǎng)格;
  • ax.text 為圖形添加文字,前兩個(gè)參數(shù)表示添加的文字在坐標(biāo)系中的位置;
    可以看到設(shè)置各種屬性非常簡(jiǎn)單,這些設(shè)置屬性的方法還有很多可選參數(shù),篇幅有限就不一一介紹了。


    image.png

有的時(shí)候,我們想指定繪制的曲線的顏色,設(shè)置圖例,該怎么辦呢?示例代碼:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 1,100)
fig = plt.figure()
ax = fig.add_subplot(1,1,1)

major_ticks = np.arange(0, 1.1, 0.1)   #大數(shù)字尺度
minor_ticks = np.arange(0, 1.1, 0.01) #更細(xì)的小網(wǎng)格尺度

ax.set_xticks(major_ticks)
ax.set_xticks(minor_ticks, minor=True)
ax.set_yticks(major_ticks)
ax.set_yticks(minor_ticks, minor=True)

ax.set_xlabel("X axis")
ax.set_ylabel("Y axis")
ax.grid(which='minor', alpha=0.1) #alpha是透明度
ax.grid(which='major', alpha=0.2)

plt.title("簡(jiǎn)書(shū)")

plt.plot(x, x ** (1/8), 'b--', label=r'y = x^1/8')
plt.plot(x, x ** 8, 'r--', label=r'y = x^8')

plt.plot(x, x ** (1/2), 'r.', label=r'y = x^1/2')
plt.plot(x, x ** 2, 'b.', label=r'y = x^2')

plt.plot(x, x, 'g-', label=r'y = x')

plt.legend()
plt.show()
image.png

在上面的代碼中,通過(guò) np.linspace(0, 1, 100) 創(chuàng)建了 100 個(gè)值,這些值平均分布在 0 到 1 的范圍內(nèi)。接著我們?cè)?Axes 對(duì)象上繪制了 5 條曲線,這 5 條曲線分別對(duì)應(yīng)于 5 個(gè)函數(shù),函數(shù)名稱(chēng)已經(jīng)通過(guò)圖例的形式顯示在圖形上了。

其中,我們使用類(lèi)似于 ax.plot(x, x ** (1/8), 'b--', label=r' y = x^{1/8}y=x 1/8 ') 方法繪制曲線,該方法有四個(gè)參數(shù),前兩個(gè)參數(shù)分別對(duì)應(yīng)于 X, Y 軸的數(shù)據(jù),繪圖時(shí)會(huì)根據(jù) x 和 x ** (1/8) 值序列確定曲線的位置。第三個(gè)參數(shù) b-- 代表繪制的曲線是 blue 藍(lán)色,樣式是虛線。matplotlib 中有多種指定線條顏色和樣式的辦法,如 r-- 指明紅色虛線,r. 代表紅色點(diǎn),更多的樣式可以參考 matplotlib 文檔。最后一個(gè)參數(shù) label=r'y = x^{1/8}') 設(shè)置了線條的標(biāo)簽,該標(biāo)簽文字內(nèi)容是數(shù)學(xué)公式,matplotlib 支持 LaTeX 語(yǔ)法顯示各種數(shù)學(xué)公式。

有的時(shí)候,我們想在圖形上顯示曲線標(biāo)簽信息,這個(gè)時(shí)候可以使用 ax.legend() 方法,該方法使用曲線的標(biāo)簽信息(也就是繪制曲線是傳入的 label 參數(shù))自動(dòng)生成圖例,并將圖例放到圖形合適的位置。

最后為了方便查看圖形,我們將圖形的視口坐標(biāo)設(shè)置成了 [0, 1, 0, 1] ,代表X, Y坐標(biāo)軸范圍都設(shè)置為 0 到 1。如果圖形顯示范圍超過(guò)了 0 到 1 的范圍,則會(huì)自動(dòng)截取 0 到 1 范圍內(nèi)的圖形進(jìn)行顯示。

matplotlib 繪圖時(shí)可以設(shè)置很多屬性,比如設(shè)置注解,設(shè)置外部圖片等,這些都可以通過(guò)調(diào)用 Axes 對(duì)象相應(yīng)方法進(jìn)行,更多的用法可以查看 Axes 對(duì)象 API 文檔。

常用圖形

在數(shù)據(jù)分析中,經(jīng)常需要繪制各種圖形,下面我們看下一些常用圖形在 matplotlib 中的繪制方法。為節(jié)省篇幅,以下說(shuō)明代碼中出現(xiàn)的 fig,ax 對(duì)象已經(jīng)通過(guò)以下代碼創(chuàng)建:

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(1,1,1)

由于 matplotlib 顯示圖形時(shí)的循環(huán)原因,每次創(chuàng)建新的圖形上都需要重新執(zhí)行以上代碼。

線形圖

線形圖更多時(shí)候用于觀察變量之間的函數(shù)關(guān)系,比如如果變量之間滿(mǎn)足 y = 2xy=2x 的線性關(guān)系,那么繪制的圖形應(yīng)該是一條直線(比如上文中出現(xiàn)的例子),如果沒(méi)有關(guān)系,則是一堆涂鴉。在 matplotlib 中可以使用 Axes.plot 方法繪制線形圖:

x = np.random.randn(100)
y = np.random.randn(100)

ax.plot(x, y)
plt.show()

上面的代碼創(chuàng)建了兩個(gè)隨機(jī)的數(shù)值序列,這兩個(gè)數(shù)值序列之間理論上沒(méi)有任何關(guān)系,顯示的圖形如下:

image.png

直方圖

直方圖可以顯示數(shù)據(jù)分布情況,X 軸一般是統(tǒng)計(jì)的樣本,而 Y 是樣本對(duì)應(yīng)的統(tǒng)計(jì)度量。為了構(gòu)建直方圖,第一步是將值的范圍分段,即將整個(gè)值的范圍分成一系列間隔,然后計(jì)算每個(gè)間隔中有多少值。 這些值通常被指定為連續(xù)的,不重疊的變量間隔。 間隔必須相鄰,并且通常是(但不是必須的)相等的大小。在 matplotlib 中可以使用 Axes.hist 方法繪制直方圖:

data = np.random.normal(0, 20, 1000)
bins = np.arange(-100, 100, 5)
ax.hist(data, bins=bins)
plt.show()

上面的代碼首先通過(guò) np.random.normal 方法,在 0 到 20 的范圍產(chǎn)生 1000 個(gè)符合正態(tài)分布的數(shù)據(jù)值,然后通過(guò) np.arange(-100, 100, 5) 創(chuàng)建了 X 軸的區(qū)間刻度。創(chuàng)建的圖形類(lèi)似

image.png

散點(diǎn)圖

散點(diǎn)圖,將所有的數(shù)據(jù)值在圖形中繪制成點(diǎn),這樣有多少數(shù)據(jù)值在圖形中就會(huì)有多少個(gè)點(diǎn)。通過(guò)這些數(shù)據(jù)點(diǎn)可以看出數(shù)據(jù)值的分布模式,比如是否有聚類(lèi)模式,或者相關(guān)關(guān)系或者發(fā)現(xiàn)離群點(diǎn)。在 matplotlib 中可以通過(guò) Axes.scatter 繪制散點(diǎn)圖:

x = np.arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
ax.scatter(x, y)
plt.show()

為了模擬散點(diǎn)圖,我們先通過(guò) np.arange(1, 101) 創(chuàng)建了 100 個(gè)數(shù)據(jù)值,接著基于此創(chuàng)建了 100 個(gè) Y 軸數(shù)據(jù),可以看到這里兩組數(shù)據(jù)值之間有相關(guān)關(guān)系,因?yàn)槭腔诰€性關(guān)系然后加

箱線圖

箱線圖可以看出數(shù)據(jù)的分散程度,異常值等信息,箱線圖根據(jù)一組數(shù)據(jù)的以下 5 個(gè)統(tǒng)計(jì)值進(jìn)行繪制:

  • 最小值;
  • 第1四分位數(shù);
  • 中位數(shù);
  • 第3四分位數(shù);
  • 最大值;
    其中四分位數(shù),是指將一組數(shù)據(jù)值按大小排序后分成四等分,每一部分包含 1/4 的數(shù)據(jù),這種劃分的分割點(diǎn)就是四分位數(shù)。其中第1部分和第2部分的分割點(diǎn)稱(chēng)為第1分位數(shù) Q1, 也被稱(chēng)為第25百分位數(shù),第3部分和第4部分的分割點(diǎn)稱(chēng)為第3四分位數(shù)Q3,也被稱(chēng)為第75百分位數(shù)。而第二部分和第三部分的分割點(diǎn)是第2四分?jǐn)?shù),也就是中位數(shù)。其中四分位距 IQR是指第三四分位數(shù)和第一分四分位數(shù)的差,也就是IQR=Q3-Q1四分位距反映了中間 50% 數(shù)據(jù)的離散程度,數(shù)值越小代表數(shù)據(jù)越集中,越大代表數(shù)據(jù)越分散。

在 matplotlib 中可以使用 Axes.boxplot 方法繪制箱線圖:

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(1,1,1)

# 產(chǎn)生 50 個(gè)小于 100 的隨機(jī)數(shù)
spread = np.random.rand(50) * 100
# 產(chǎn)生 25 個(gè)值為 50 的數(shù)據(jù)
center = np.ones(25) * 50
# 異常值
outlier_high = np.random.rand(10) * 100 + 100
outlier_low = np.random.rand(10) * -100
data = np.concatenate((spread, center, outlier_high, outlier_low), 0)
ax.boxplot(data)
plt.show()

上面的代碼中,我們特意創(chuàng)建了 data 數(shù)據(jù),可以推斷出該數(shù)據(jù)的中位數(shù)是 50,還有一些其他異常值,繪制的圖形如下:

image.png

Pandas 繪圖

matplotlib 繪制圖像已經(jīng)夠方便,但是更多的時(shí)候我們使用 Pandas 分析數(shù)據(jù),并把數(shù)據(jù)保存在 DataFrame 數(shù)據(jù)對(duì)象中。幸運(yùn)的是,Pandas 已經(jīng)高度整合了 matplotlib, 可以直接直接調(diào)用DataFrame 對(duì)象的某些方法進(jìn)行繪圖,更加方便的時(shí)候 DataFrame 的標(biāo)簽信息(列名稱(chēng))會(huì)自動(dòng)繪制到圖形上。

以下示例代碼中的 Series, Dataframe, np, plt, pd 已經(jīng)通過(guò)以下代碼導(dǎo)入:

In [82]: import matplotlib.pyplot as plt

In [83]: import numpy as np

In [84]: import pandas as pd

In [85]: from pandas import Series, DataFrame

可以直接在 Series 對(duì)象上繪制線形圖,如下代碼:

In [79]: s = Series(np.random.randn(10).cumsum(), index=np.arange(0, 100, 10))

In [80]: s.plot()
Out[80]: <matplotlib.axes._subplots.AxesSubplot at 0x117e3e588>

In [81]: plt.show()

或者在 DataFrame 對(duì)象上繪制箱線圖:

In [86]: df = pd.DataFrame(np.random.rand(5,4), columns=['A', 'B', 'C', 'D'])

In [87]: df.boxplot()
Out[87]: <matplotlib.axes._subplots.AxesSubplot at 0x115c2f5f8>

In [88]: plt.show()

可以看到非常方便,在前文中展示的各種常用圖形,Pandas 都可以直接進(jìn)行繪制,并自動(dòng)添加標(biāo)簽等信息。

其他繪圖工具

在 Python 數(shù)據(jù)分析世界中,除了 matplotlib 外,還有其他許多繪圖工具。每一種工具側(cè)重點(diǎn)都有所不同,但是其中 Seaborn 最值得介紹。Seaborn 建立在 matplotlib 之上,提供了更高級(jí)更方便的使用方式。在之前的 matplotlib 學(xué)習(xí)中,已經(jīng)發(fā)現(xiàn)如果想通過(guò) matplotlib 繪制出比較精美的圖形還是比較困難的,需要定制各個(gè)屬性,但是通過(guò) Seaborn 卻非常簡(jiǎn)單。通過(guò) Seaborn 可以很方面繪制出線各種常見(jiàn)關(guān)系的圖形,比如聚類(lèi)關(guān)系,線性關(guān)系,分布關(guān)系等,在 IPython 中輸入下面的代碼,就可以看到精美的圖形了:

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
np.random.seed(sum(map(ord, "aesthetics")))

def sinplot(flip=1):
    x = np.linspace(0, 14, 100)
    for i in range(1, 7):
        plt.plot(x, np.sin(x + i * .5) * (7 - i) * flip)

sns.set()
sinplot()

plt.show()

如下圖:


image.png

除了 Seaborn 之外還有其他的一些繪圖工具,比如 Bokeh 。Bokeh 是一個(gè)現(xiàn)代化的繪圖工具,底層使用 D3.js 進(jìn)行繪圖,也就是說(shuō) Bokeh 繪制的圖形是基于瀏覽器顯示的,這也非常符合當(dāng)今的技術(shù)潮流,而且繪制的圖形交互功能更加強(qiáng)大。

在 IPython 終端中輸入下面的代碼,等待一會(huì)(網(wǎng)絡(luò)情況差的情況下時(shí)間比較長(zhǎng)一些),Bokeh 會(huì)自動(dòng)打開(kāi)瀏覽器線上顯示圖形:

import numpy as np

from bokeh.layouts import gridplot
from bokeh.plotting import figure, show, output_file

# sin 曲線
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)

p = figure(title="jianshu")

p.circle(x,   y, legend="sin(x)")
p.circle(x, 2*y, legend="2*sin(x)", color="orange")
p.circle(x, 3*y, legend="3*sin(x)", color="green")

show(p)

圖形顯示如下:


image.png

Bokeh 功能豐富,如果想嘗試除了 matplotlib 之外的繪圖工具,非常值得一試。

總結(jié)

本節(jié)實(shí)驗(yàn)主要講解了 matplotlib 繪圖的基本功能,涉及到 matplotlib 繪圖時(shí)的常用屬性設(shè)置,以及一些常用圖形的繪制方法。在數(shù)據(jù)分析的世界中,繪圖可視化不僅僅是發(fā)現(xiàn)數(shù)據(jù)分布規(guī)律,相關(guān)性等關(guān)系的有力工具,也可以用于展示數(shù)據(jù)優(yōu)化結(jié)果。所以請(qǐng)努力學(xué)習(xí)實(shí)踐本章節(jié)內(nèi)容。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容