用 Seaborn 畫出好看的分布圖(Python)

jopen 9年前發布 | 295K 次閱讀 Python Python開發

%matplotlib inline

Populating the interactive namespace from numpy and matplotlib

import seaborn as sns import numpy as np from numpy.random import randn import matplotlib as mpl import matplotlib.pyplot as plt from scipy import stats

style set 這里只是一些簡單的style設置

sns.set_palette('deep', desat=.6) sns.set_context(rc={'figure.figsize': (8, 5) } ) np.random.seed(1425)

figsize是常用的參數.</pre>

最簡單的hist (直方圖)

最簡單的hist是使用一列數據(series)作為輸入, 也不用考慮其它的參數.

data = randn(75)
plt.hist(data)

(array([ 2., 5., 4., 10., 12., 16., 7., 7., 6., 6.]), array([-2.04713616, -1.64185099, -1.23656582, -0.83128065, -0.42599548, -0.02071031, 0.38457486, 0.78986003, 1.1951452 , 1.60043037, 2.00571554]), <a list of 10 Patch objects>)</pre>

用 Seaborn 畫出好看的分布圖(Python)

# 增加一些參數, 就能畫出別樣的風采
data = randn(100)
plt.hist(data, bins=12, color=sns.desaturate("indianred", .8), alpha=.4)

(array([ 2., 3., 3., 11., 10., 15., 10., 17., 10., 8., 7., 4.]), array([-2.56765228, -2.1665249 , -1.76539753, -1.36427015, -0.96314278, -0.5620154 , -0.16088803, 0.24023935, 0.64136672, 1.0424941 , 1.44362147, 1.84474885, 2.24587623]), <a list of 12 Patch objects>)</pre>

用 Seaborn 畫出好看的分布圖(Python)

# 以上數據是單總體, 雙總體的hist

data1 = stats.poisson(2).rvs(100) data2 = stats.poisson(5).rvs(500)

maxdata = np.r[data1, data2].max() bins = np.linspace(0, max_data, max_data+1)

plt.hist(data1)

首先將2個圖形分別畫到figure中

plt.hist(data1, bins, normed=True, color="#FF0000", alpha=.9) plt.figure() plt.hist(data2, bins, normed=True, color="#C1F320", alpha=.5)

(array([ 0.006, 0.03 , 0.082, 0.116, 0.17 , 0.214, 0.152, 0.098, 0.06 , 0.046, 0.018, 0.008]), array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]), <a list of 12 Patch objects>)</pre>

用 Seaborn 畫出好看的分布圖(Python)

用 Seaborn 畫出好看的分布圖(Python)

# 觀察下面圖形 可以看出nomed參數的作用 --

首先還是各自繪出自己的分布hist, 然后將二者重合部分用第三顏色加以區別.

plt.hist(data1, bins, normed=True, color="#FF0000", alpha=.9) plt.hist(data2, bins, normed=True, color="#C1F320", alpha=.5)

(array([ 0.006, 0.03 , 0.082, 0.116, 0.17 , 0.214, 0.152, 0.098, 0.06 , 0.046, 0.018, 0.008]), array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]), <a list of 12 Patch objects>)</pre>

用 Seaborn 畫出好看的分布圖(Python)

# hist 其它參數
x = stats.gamma(3).rvs(5000);

plt.hist(x, bins=80) # 每個bins都有分界線

若想讓圖形更連續化 (去除中間bins線) 用histtype參數

plt.hist(x, bins=80, histtype="stepfilled", alpha=.8)

(array([ 19., 27., 53., 97., 103., 131., 167., 176., 196., 215., 214., 202., 197., 153., 202., 214., 181., 160., 175., 179., 148., 148., 117., 130., 125., 122., 100., 102., 80., 85., 66., 67., 58., 51., 56., 42., 52., 36., 37., 26., 29., 19., 26., 21., 26., 19., 16., 12., 12., 17., 12., 9., 10., 4., 4., 6., 4., 7., 3., 6., 1., 3., 3., 1., 1., 2., 0., 0., 1., 2., 3., 1., 2., 3., 1., 2., 1., 0., 0., 2.]), array([ 0.13431232, 0.28186933, 0.42942633, 0.57698333, 0.72454033, 0.87209734, 1.01965434, 1.16721134, 1.31476834, 1.46232535, 1.60988235, 1.75743935, 1.90499636, 2.05255336, 2.20011036, 2.34766736, 2.49522437, 2.64278137, 2.79033837, 2.93789538, 3.08545238, 3.23300938, 3.38056638, 3.52812339, 3.67568039, 3.82323739, 3.9707944 , 4.1183514 , 4.2659084 , 4.4134654 , 4.56102241, 4.70857941, 4.85613641, 5.00369341, 5.15125042, 5.29880742, 5.44636442, 5.59392143, 5.74147843, 5.88903543, 6.03659243, 6.18414944, 6.33170644, 6.47926344, 6.62682045, 6.77437745, 6.92193445, 7.06949145, 7.21704846, 7.36460546, 7.51216246, 7.65971947, 7.80727647, 7.95483347, 8.10239047, 8.24994748, 8.39750448, 8.54506148, 8.69261849, 8.84017549, 8.98773249, 9.13528949, 9.2828465 , 9.4304035 , 9.5779605 , 9.7255175 , 9.87307451, 10.02063151, 10.16818851, 10.31574552, 10.46330252, 10.61085952, 10.75841652, 10.90597353, 11.05353053, 11.20108753, 11.34864454, 11.49620154, 11.64375854, 11.79131554, 11.93887255]), <a list of 1 Patch objects>)</pre>

用 Seaborn 畫出好看的分布圖(Python)

# 上面的多總體hist 還是獨立作圖, 并沒有將二者結合,

使用jointplot就能作出聯合分布圖形, 即, x總體和y總體的笛卡爾積分布

不過jointplot要限于兩個等量總體.

jointplot還是非常實用的, 對于兩個連續型變量的分布情況, 集中趨勢能非常簡單的給出.

比如下面這個例子

x = stats.gamma(2).rvs(5000) y = stats.gamma(50).rvs(5000) with sns.axes_style("dark"): sns.jointplot(x, y, kind="hex")</pre>

用 Seaborn 畫出好看的分布圖(Python)

# 下面用使用真實一點的數據作個dmeo
import pandas as pd
from pandas import read_csv

df = read_csv("test.csv", index_col='index') df[:2]</pre>

</tr>

</tr> </tbody>

</tr>

</tr> </tbody> </table> </div>

clean_df = df[df['salary_net'] < 10000]

sub_df = pd.DataFrame(data=clean_df, columns=['salary_net', 'month_repay'] )

with sns.axes_style("dark"): sns.jointplot('salary_net', 'month_repay', data=sub_df, kind="hex") plt.ylim([0, 10000]) plt.xlim([0, 10000])</pre>

用 Seaborn 畫出好看的分布圖(Python)

注: jointplot除了作圖, 還會給出x, y的相關系數(pearson_r) 和r = 0 的假設檢驗p值.

</blockquote>

下面學習新的圖形: kdeplot, rugplot

# rugplot

rugplot 是比Histogram更加直觀的 "Histogram"

data = randn(80) plt.hist(data, alpha=0.3, color='#ffffff') sns.rugplot(data)

<matplotlib.axes._subplots.AxesSubplot at 0x226826a0></pre>

用 Seaborn 畫出好看的分布圖(Python)

# example

下面的圖看上去復雜, 不過也很好理解, 從一個樣本點生成一個bell-curve

這樣看bell集中的地方就是數據最密集的地方.

sns.rugplot(data, color='indianred') xx = np.linspace(-4, 4, 100)

計算bandwidth

bandwidth = ( ( 4data.std() ** 5)/(3 len(data))) .2 bandwidth = len(data) (-1. /5)

0.416276603701 print bandwidth

kernels = [] for d in data:

# basis function as a gaussian PDF
kernel = stats.norm(d, bandwidth).pdf(xx)
kernels.append(kernel)

# Scale for plotting
kernel /= kernel.max()
kernel *= .4

plt.plot(xx, kernel, "#888888", alpha=.18)

plt.ylim(0, 1)

0.416276603701

(0, 1)</pre>

用 Seaborn 畫出好看的分布圖(Python)

# example 2

set-Up

f, (ax1, ax2) = plt.subplots(2, 1, sharex=True)

color_palette 就是要畫圖用的 "調色盤"

c1, c2 = sns.color_palette("husl", 3)[:2]

summed kde

summed_kde = np.sum(kernels, axis=0) ax1.plot(xx, summed_kde, c=c1) sns.rugplot(data, c=c1, ax=ax1) ax1.set_title("summed basis function")

density estimate

scipy_kde = stats.gaussian_kde(data)(xx) ax2.plot(xx, scipy_kde, c=c2) sns.rugplot(data, c=c2, ax=ax2) ax2.set_yticks([]) # no ticks of y ax2.set_title("scipy gaussian_kde") f.tight_layout()</pre>

用 Seaborn 畫出好看的分布圖(Python)

有了上面的知識, 就能理解kdeplot的作用了.

sns.kdeplot(data, shade=True)

<matplotlib.axes._subplots.AxesSubplot at 0x2356ba20></pre>

用 Seaborn 畫出好看的分布圖(Python)

# 比較bw(bandwidth) 作用

pal = sns.blend_palette([sns.desaturate("royalblue", 0), "royalblue"], 5) bws = [.1, .25, .5, 1, 2]

for bw, c in zip(bws, pal): sns.kdeplot(data, bw=bw, color=c, lw=1.8, label=bw)

plt.legend(title="kernel bandwidth value") sns.rugplot(data, color="#CF3512")

<matplotlib.axes._subplots.AxesSubplot at 0x225db9b0></pre>

用 Seaborn 畫出好看的分布圖(Python)

# 比較不同的kernels
kernels = ["biw", "cos", "epa", "gau", "tri", "triw"]

for k, c in zip(kernels, pal): sns.kdeplot(data, kernel=k, color=c, label=k) plt.legend()

<matplotlib.legend.Legend at 0x225db278></pre>

用 Seaborn 畫出好看的分布圖(Python)

# cut, clip 參數用于對outside data ( data min左, max右) 的預測 填充
with sns.color_palette('Set2'):
    f, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 8), sharex=True)
    for cut in[4, 3, 2]:
        sns.kdeplot(data, cut=cut, label=cut, lw=cut*1.5, ax=ax1)

for clip in[1, 2, 3]:
    sns.kdeplot(data, clip=(-clip, clip), label=clip, ax=ax2)</pre> <p><img alt="用 Seaborn 畫出好看的分布圖(Python)" src="https://simg.open-open.com/show/fbb22b29a7959902c5bb644dbc41266e.png" width="486" height="481" /> </p>

# 利用kdeplot來確定兩個sample data 是否來自于同一總體
f, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(8, 6))
c1, c2, c3 = sns.color_palette('Set1', 3)

dist1, dist2, dist3 = stats.norm(0, 1).rvs((3, 100)) dist3 = pd.Series(dist3 + 2, name='dist3')

dist1, dist2是兩個近似正態數據, 擁有相同的中心和擺動程度

sns.kdeplot(dist1, shade=True, color=c1, ax=ax1) sns.kdeplot(dist2, shade=True, color=c2, label='dist2', ax=ax1)

dist3 分布3 是另一個近正態數據, 不過中心為2.

sns.kdeplot(dist1, shade=True, color=c2, ax=ax2) sns.kdeplot(dist3, shade=True, color=c3, ax=ax2)

<matplotlib.axes._subplots.AxesSubplot at 0x2461a240></pre>

用 Seaborn 畫出好看的分布圖(Python)

# kdeplot是密度圖.

對概率密度統計熟悉的人還會想到的是累積密度圖

kdeplot 參數 cumulative

with sns.color_palette("Set1"): for d, label in zip(data, list("ABC")): sns.kdeplot(d, cumulative=True, label=label)</pre>

用 Seaborn 畫出好看的分布圖(Python)

# vertical 參數 把剛才的圖形旋轉90度
plt.figure(figsize=(4, 8))
data = stats.norm(0, 1).rvs((3, 100)) + np.arange(3)[:, None]

with sns.color_palette("Set2"): for d, label in zip(data, list("ABC")): sns.kdeplot(d, vertical=True, shade=True, label=label)

plt.hist(data, vertical=True)

error vertical不是每個函數都具有的</pre>

用 Seaborn 畫出好看的分布圖(Python)

多維數據的kdeplot

data = np.random.multivariate_normal([0, 0], [[1, 2], [2, 20]], size=1000)
data = pd.DataFrame(data, columns=["X", "Y"])
mpl.rc("figure", figsize=(6, 6))

sns.kdeplot(data)

<matplotlib.axes._subplots.AxesSubplot at 0x23104320></pre>

用 Seaborn 畫出好看的分布圖(Python)

# 更多的還是用來畫二維數據的density plot
sns.kdeplot(data.X, data.Y, shade=True, bw="silverman", gridsize=50, clip=(-11, 11))

gridsize參數用來指定grid尺寸

cut clip 參數類似之前提到過的

cmap則是用來color map映射, 相當于一個color小帽子(mask)

<matplotlib.axes._subplots.AxesSubplot at 0x2768f240></pre>

用 Seaborn 畫出好看的分布圖(Python)

sns.kdeplot(data.X, data.Y, shade=True, bw="silverman", gridsize=50, clip=(-11, 11),  cmap="BuGn_d")
sns.kdeplot(data.X, data.Y, shade=True, bw="silverman", gridsize=50, clip=(-11, 11),  cmap="Purples")

<matplotlib.axes._subplots.AxesSubplot at 0x26c6fa20></pre>

用 Seaborn 畫出好看的分布圖(Python)

好了. 那再讓我來回來想想jointplot

之前jointplot用了 kind=hex, 那么當見過了kde核函數分布圖后, 可以把這二者結合到一起.

with sns.axes_style('white'):
    sns.jointplot('X', 'Y', data, kind='kde')

用 Seaborn 畫出好看的分布圖(Python)

hist增強版 - distplot

# distplot 簡版就是hist 加上一根density curve
sns.set_palette("hls")
mpl.rc("figure", figsize=(9, 5))
data = randn(200)
sns.distplot(data)

<matplotlib.axes._subplots.AxesSubplot at 0x25eb34e0></pre>

用 Seaborn 畫出好看的分布圖(Python)

# 當然慢慢地就發現distplot的功能, 遠比hist強大. 
sns.distplot(data, kde=True, rug=True, hist=True)

更細致的, 來用各kwargs來指定 (參數的參數dict)

sns.distplot(data, kde_kws={"color": "seagreen", "lw":3, "label" : "KDE" }, hist_kws={"histtype": "stepfilled", "color": "slategray" })

<matplotlib.axes._subplots.AxesSubplot at 0x261ffe80></pre>

用 Seaborn 畫出好看的分布圖(Python)

好了. 下面的圖很熟悉, boxplot 與 violinplot

boxplot, 連續數據的另一種分布式描述. 以five - figures作為大概的集中趨勢, 離散趨勢的統計量.
violinplot是與之類似, 它是在boxplot基礎上增加了density curve (也就是"小提琴"的兩側曲線)

A violin plot is a method of plotting numeric data. It is a box plot with a rotated kernel density plot on each side.[1]

</blockquote>

more info at wiki

# first 先來看boxplot
sns.set(rc={"figure.figsize": (6, 6)})
data = [randn(100), randn(120) + 1.5]
plt.boxplot(data)

這是一個簡單版"dataframe", 由兩列不等長的series(array)組成, 沒有index columns所以在圖中默認用1,2,3代替

{'boxes': [<matplotlib.lines.Line2D at 0x25747908>, <matplotlib.lines.Line2D at 0x26995048>], 'caps': [<matplotlib.lines.Line2D at 0x2574c6d8>, <matplotlib.lines.Line2D at 0x2574cc50>, <matplotlib.lines.Line2D at 0x26995d68>, <matplotlib.lines.Line2D at 0x2699f320>], 'fliers': [<matplotlib.lines.Line2D at 0x2576e780>, <matplotlib.lines.Line2D at 0x2699fe10>], 'means': [], 'medians': [<matplotlib.lines.Line2D at 0x2576e208>, <matplotlib.lines.Line2D at 0x2699f898>], 'whiskers': [<matplotlib.lines.Line2D at 0x25747b38>, <matplotlib.lines.Line2D at 0x2574c160>, <matplotlib.lines.Line2D at 0x26995278>, <matplotlib.lines.Line2D at 0x269957f0>]}</pre>

用 Seaborn 畫出好看的分布圖(Python)

# 上面的圖形是mpl module畫出來的, 比較"ugly"

來看看seaborn畫出來的樣貌

sns.boxplot(data)

... 可能只是兩種不同的風格吧!

<matplotlib.axes._subplots.AxesSubplot at 0x26926160></pre>

用 Seaborn 畫出好看的分布圖(Python)

# 當然, 如果可以, 最好我們能指定兩組分布更多的信息
sns.boxplot(data, names=['left', 'right'], whis=np.inf, color='indianred')

<matplotlib.axes._subplots.AxesSubplot at 0x24513160></pre>

用 Seaborn 畫出好看的分布圖(Python)

# 其它參數demo
sns.boxplot(data, names=['down', 'up'],linewidth=2, widths =.5, vert=False, color='slategray')

<matplotlib.axes._subplots.AxesSubplot at 0x2673edd8></pre>

用 Seaborn 畫出好看的分布圖(Python)

# join_rm 參數 rm 是指 repeated-measures data 重復觀測

為了彰顯重復觀測的效應, 可使用join_rm參數==True

pre = randn(25) post = pre+ np.random.rand(25) sns.boxplot([pre, post], names=["left", "right"], color="coral", join_rm =True)

<matplotlib.axes._subplots.AxesSubplot at 0x2598d1d0></pre>

用 Seaborn 畫出好看的分布圖(Python)

# 下面介紹violinplot, 而且是從boxplot開始講起.

這也是非常喜歡這個module(作者)的原因, 很合我的味口

d1 = stats.norm(0, 5).rvs(100) d2 = np.concatenate([stats.gamma(4).rvs(50), -1 * stats.gamma(4).rvs(50) ]) data = pd.DataFrame(dict(d1=d1, d2=d2))

sns.boxplot(data, color="pastel", widths=.5)

<matplotlib.axes._subplots.AxesSubplot at 0x28c3c080></pre>

用 Seaborn 畫出好看的分布圖(Python)

# 看上面兩個boxplot 分布是很接近的, 但有多像? 無法定量

簡單的boxplot是定性的描述, 用來比較時更不能定量比較相似程度

sns.violinplot(data, color="pastel")

<matplotlib.axes._subplots.AxesSubplot at 0x29058240></pre>

用 Seaborn 畫出好看的分布圖(Python)

# 這個時候 2個sample分布就不像了...

    boxplot violinplot 常常用來 比較 一個分組(離散) X 一個連續變量的各組差異

因此若有DataFrame結構, 要盡量學著使用groupby操作.

y = np.random.randn(200) g = np.random.choice(list('abcdef'), 200) for i, l in enumerate('abcdef'): y[g == l] += i // 2

df = pd.DataFrame(dict(score=y, group=g)) sns.boxplot(df.score, df.group)

<matplotlib.axes._subplots.AxesSubplot at 0x2908fe80></pre>

用 Seaborn 畫出好看的分布圖(Python)

# 到最后, 我看到了作者用到了我特別喜歡的一個詞 tune

violinplot 就相當于是對boxplot一個tuning的過程, 哦, 想到了老羅.

sns.violinplot(df.score, df.group, color="Paired", bw=1)

<matplotlib.axes._subplots.AxesSubplot at 0x28feec88></pre>

用 Seaborn 畫出好看的分布圖(Python)

# 關于names(組名稱list), 默認的畫圖順序是 array順序, 也能額外用order參數指定
order = list('cbafed')
sns.boxplot(df.score, df.group, order=order, color='PuBuGn_d')

<matplotlib.axes._subplots.AxesSubplot at 0x24ce4d68></pre>

用 Seaborn 畫出好看的分布圖(Python)

在復雜的violinplot基礎上再tune一點

# 使用參數 inner

inner : {‘box’ | ‘stick’ | ‘points’}

Plot quartiles or individual sample values inside violin.

y = np.random.randn(200) g = np.random.choice(list("abcdef"), 200) for i, l in enumerate("abcdef"): y[g == l] += i // 2 df = pd.DataFrame(dict(score=y, group=g)) sns.boxplot(df.score, df.group);</pre>

用 Seaborn 畫出好看的分布圖(Python)

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!

department typecity product credit ddate month_repay apply_amont month_repay_real amor tst_amount salary_net LTI DTI pass deny
index














13652622 gedai ordi elite CR8 2015/5/29 12:27 2000 40000 1400.90 36 30000 1365.30 21.973193 0.610366 1 0
13680088 gedai ordi xinxin CR16 2015/6/3 18:38 8000 100000 3589.01 36 70000 3598.66 19.451685 0.540325 1 0
  • sesese色