Python统计可视化库Seaborn

易红发 [email protected]

  大家都知道Python中有一个强大的可视化库matplotlib,其中matplotlib.pyplot也是针对统计可视化,可问题在于matplotlib太过繁复,这里推荐另一个统计可视化库Seaborn,只需简单的几行代码,就可以画出相当漂亮的统计图。
  另外,如果需要制作交互式图表,Python中我推荐bokeh库
  注:本分享可直接下载,然后用IPython notebook(现在叫jupyter)运行。

可视化连续数据集

In [1]:
%matplotlib inline
In [2]:
import numpy as np
import pandas as pd
from scipy import stats, integrate
import matplotlib.pyplot as plt
In [3]:
import seaborn as sns
sns.set(color_codes=True)
In [4]:
np.random.seed(sum(map(ord, "distributions")))

  • 可视化单变量

In [8]:
x = np.random.normal(size=100)
sns.distplot(x)#默认增加趋势线
Out[8]:
<matplotlib.axes._subplots.AxesSubplot at 0x1ede3f60>
In [9]:
sns.distplot(x, kde=False, rug=True)#删除趋势线,增加地毯图
Out[9]:
<matplotlib.axes._subplots.AxesSubplot at 0x1f0c27f0>
In [10]:
sns.distplot(x, bins=20, kde=False, rug=True)#将箱数设置为20
Out[10]:
<matplotlib.axes._subplots.AxesSubplot at 0x1f672390>
In [11]:
sns.distplot(x, hist=False, rug=True)#要趋势线,不要直方图
Out[11]:
<matplotlib.axes._subplots.AxesSubplot at 0x1fca87f0>
In [13]:
sns.kdeplot(x, shade=True)#也可以直接使用线图
Out[13]:
<matplotlib.axes._subplots.AxesSubplot at 0x2038df98>

一个新的参数 bw(banwidth)类似于直方图里面的箱数

In [15]:
sns.kdeplot(x)
sns.kdeplot(x, bw=.2, label="bw:0.2")
sns.kdeplot(x, bw=2, label="bw:2")
plt.legend()
Out[15]:
<matplotlib.legend.Legend at 0x20f41940>
In [20]:
sns.kdeplot(x, shade=True, cut=0)#删除极端值
sns.rugplot(x)
Out[20]:
<matplotlib.axes._subplots.AxesSubplot at 0x201fb7b8>

  • 可视化双变量

In [23]:
mean, cov = [0, 1], [(1, .5), (.5, 1)]
data = np.random.multivariate_normal(mean, cov, 200)
df = pd.DataFrame(data, columns=["x", "y"])
In [25]:
sns.jointplot(x="x", y="y", data=df)#默认散点图
Out[25]:
<seaborn.axisgrid.JointGrid at 0x20379898>
In [26]:
x, y = np.random.multivariate_normal(mean, cov, 1000).T
with sns.axes_style("white"):
    sns.jointplot(x=x, y=y, kind="hex", color="k")#六边分图
In [27]:
sns.jointplot(x="x", y="y", data=df, kind="kde")
Out[27]:
<seaborn.axisgrid.JointGrid at 0x226196d8>
In [28]:
f, ax = plt.subplots(figsize=(6, 6))
sns.kdeplot(df.x, df.y, ax=ax)#通过kdeplot画图
sns.rugplot(df.x, color="g", ax=ax)
sns.rugplot(df.y, vertical=True, ax=ax);

  • 可视化多对关系

In [6]:
iris = sns.load_dataset("iris")
sns.pairplot(iris)
Out[6]:
<seaborn.axisgrid.PairGrid at 0x20e45978>

可视化线性关系

In [7]:
np.random.seed(sum(map(ord, "regression")))
In [8]:
tips = sns.load_dataset('tips')

  • 绘制函数

regplot()和lmplot()两个函数,前一个接受各种数据输入,后一种更为严格

In [10]:
sns.regplot(x="total_bill", y="tip", data=tips)
Out[10]:
<matplotlib.axes._subplots.AxesSubplot at 0x3e32470>
In [14]:
sns.lmplot(x="total_bill", y="tip", data=tips)

有时候数据集所产生的散点图并不是最优的

In [15]:
sns.lmplot(x='size', y='tip', data=tips)
Out[15]:
<seaborn.axisgrid.FacetGrid at 0x242cd438>

改进的方法,一种是增加一些随机噪音('jitter')

In [16]:
sns.lmplot(x='size', y='tip', data=tips, x_jitter=.05)
Out[16]:
<seaborn.axisgrid.FacetGrid at 0x2544d4a8>

另一种方法是根据每个离散值的中心,以绘制趋势

In [17]:
sns.lmplot(x='size', y='tip', data=tips, x_estimator=np.mean)
Out[17]:
<seaborn.axisgrid.FacetGrid at 0x240b4898>

  • 适应各种模型

In [18]:
anscombe = sns.load_dataset('anscombe')
In [21]:
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'I'"),
           ci=None, scatter_kws={"s": 80})
Out[21]:
<seaborn.axisgrid.FacetGrid at 0x240a8cf8>

上图是合适的,然而下图却不是合适模型

In [22]:
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'II'"),
           ci=None, scatter_kws={"s": 80})
Out[22]:
<seaborn.axisgrid.FacetGrid at 0x2565a208>

此时,非线性模型更为合适,这里用二次模型

In [23]:
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'II'"),
           order=2, ci=None, scatter_kws={"s": 80})
Out[23]:
<seaborn.axisgrid.FacetGrid at 0x259110b8>

另外一个问题是离群值的影响

In [24]:
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'III'"),
           ci=None, scatter_kws={"s": 80})
Out[24]:
<seaborn.axisgrid.FacetGrid at 0x25b202e8>

为了排除离群值的影响,我们可以拟合一种更为robust的模型

In [25]:
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'III'"),
           robust=True, ci=None, scatter_kws={"s": 80})
Out[25]:
<seaborn.axisgrid.FacetGrid at 0x25d3c390>

当因变量为0-1变量是,线性回归仍然有效,但有些预测值并不合理

In [26]:
tips["big_tip"] = (tips.tip / tips.total_bill) > .15
sns.lmplot(x="total_bill", y="big_tip", data=tips,
           y_jitter=.03)
Out[26]:
<seaborn.axisgrid.FacetGrid at 0x25eee240>

此时,最好拟合logistic模型

In [27]:
sns.lmplot(x="total_bill", y="big_tip", data=tips,
           logistic=True, y_jitter=.03)
Out[27]:
<seaborn.axisgrid.FacetGrid at 0x2595a8d0>

  • 在其他变量的条件下

此时,最为简单的方法就是用不同颜色表示

In [28]:
sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips)
Out[28]:
<seaborn.axisgrid.FacetGrid at 0x26393fd0>

除了改变颜色,还可以改变点的标记

In [31]:
sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips,
           markers=["o", "x"], palette="Set1")
Out[31]:
<seaborn.axisgrid.FacetGrid at 0x255a74a8>

要再增加其他变量,可以画多个图

In [32]:
sns.lmplot(x="total_bill", y="tip", hue="smoker", col="time", data=tips)
Out[32]:
<seaborn.axisgrid.FacetGrid at 0x26e5bcc0>
In [33]:
sns.lmplot(x="total_bill", y="tip", hue="smoker",
           col="time", row="sex", data=tips)
Out[33]:
<seaborn.axisgrid.FacetGrid at 0x273fedd8>

  • 控制图片大小和格式

In [37]:
f, ax = plt.subplots(figsize=(5,6))
sns.regplot(x="total_bill", y="tip", data=tips, ax=ax)
Out[37]:
<matplotlib.axes._subplots.AxesSubplot at 0x27e6acf8>

在lmplot()中,用size和aspect控制

In [38]:
sns.lmplot(x="total_bill", y="tip", col="day", data=tips,
           col_wrap=2, size=3)
Out[38]:
<seaborn.axisgrid.FacetGrid at 0x27878fd0>
In [47]:
sns.lmplot(x="total_bill", y="tip", col="day", data=tips,
           aspect=0.5)
Out[47]:
<seaborn.axisgrid.FacetGrid at 0x2c765d30>

  • 用其他方法绘制回归图

用jointplot()

In [49]:
sns.jointplot(x="total_bill", y="tip", data=tips, kind="reg", size=10)
Out[49]:
<seaborn.axisgrid.JointGrid at 0x2d6dff60>