5.md 10.8 KB
Newer Older
A
alohahahaha 已提交
1
# 可视化数据集的分布
W
init  
wizardforcel 已提交
2

飞龙 已提交
3 4
> 译者:[alohahahaha](https://github.com/alohahahaha)

W
wizardforcel 已提交
5
在处理一组数据时,您通常想做的第一件事就是了解变量的分布情况。本教程的这一章将简要介绍 seaborn 中用于检查单变量和双变量分布的一些工具。 您可能还需要查看[categorical.html](categorical.html #categical-tutorial)章节中的函数示例,这些函数可以轻松地比较变量在其他变量级别上的分布。
飞龙 已提交
6
```py
W
init  
wizardforcel 已提交
7 8 9 10 11 12 13
import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats

sns.set(color_codes=True)
```

A
alohahahaha 已提交
14
## 绘制单变量分布
W
init  
wizardforcel 已提交
15

W
wizardforcel 已提交
16
在 seaborn 中想要快速查看单变量分布的最方便的方法是使用[`distplot()`](../generated/seaborn.distplot.html#seaborn.distplot "seaborn.distplot")函数。默认情况下,该方法将会绘制直方图[histogram](https://en.wikipedia.org/wiki/Histogram)并拟合[内核密度估计] [kernel density estimate](https://en.wikipedia.org/wiki/Kernel_density_estimation) (KDE).
W
init  
wizardforcel 已提交
17 18 19 20 21 22 23 24 25

```py
x = np.random.normal(size=100)
sns.distplot(x);

```

![http://seaborn.pydata.org/_images/distributions_6_0.png](img/fea324aca2ed4416872749b8352a5412.jpg)

A
alohahahaha 已提交
26
### 直方图
W
init  
wizardforcel 已提交
27

W
wizardforcel 已提交
28 29
对于直方图我们可能很熟悉,而且 matplotlib 中已经存在`hist`函数。 直方图首先确定数据区间,然后观察数据落入这些区间中的数量来绘制柱形图以此来表征数据的分布情况。
为了说明这一点,让我们删除密度曲线并添加一个 rug plot,它在每个观察值上画一个小的垂直刻度。您可以使用[`rugplot()`](../generated/seaborn.rugplot.html#seaborn.rugplot "seaborn.rugplot") 函数来创建 rugplot 本身,但是也可以在 [`distplot()`](../generated/seaborn.distplot.html#seaborn.distplot "seaborn.distplot")中使用:
W
init  
wizardforcel 已提交
30 31 32 33 34 35 36 37

```py
sns.distplot(x, kde=False, rug=True);

```

![http://seaborn.pydata.org/_images/distributions_8_0.png](img/3a0a2053efeea3a9932d764e2d71470d.jpg)

A
alohahahaha 已提交
38
在绘制柱状图时,您的主要选择是要使用的“桶”的数量和放置它们的位置。 [`distplot()`](../generated/seaborn.distplot.html#seaborn.distplot "seaborn.distplot") 使用一个简单的规则来很好地猜测默认情况下正确的数字是多少,但是尝试更多或更少的“桶”可能会揭示数据中的其他特性:
W
init  
wizardforcel 已提交
39 40 41 42 43 44 45 46

```py
sns.distplot(x, bins=20, kde=False, rug=True);

```

![http://seaborn.pydata.org/_images/distributions_10_0.png](img/5193c672119d848c7926379d43f7f0cc.jpg)

A
alohahahaha 已提交
47
### 核密度估计
W
init  
wizardforcel 已提交
48

W
wizardforcel 已提交
49
可能你对核密度估计不太熟悉,但它可以是绘制分布形状的有力工具。和直方图一样,KDE 图沿另一个轴的高度,编码一个轴上的观测密度:
W
init  
wizardforcel 已提交
50 51 52 53 54 55 56
```py
sns.distplot(x, hist=False, rug=True);

```

![http://seaborn.pydata.org/_images/distributions_12_0.png](img/a6d422236da60cc9bd01d12080b60453.jpg)

W
wizardforcel 已提交
57
绘制 KDE 比绘制直方图更需要计算。每个观测值首先被一个以该值为中心的正态(高斯)曲线所取代:
W
init  
wizardforcel 已提交
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
```py
x = np.random.normal(0, 1, size=30)
bandwidth = 1.06 * x.std() * x.size ** (-1 / 5.)
support = np.linspace(-4, 4, 200)

kernels = []
for x_i in x:

    kernel = stats.norm(x_i, bandwidth).pdf(support)
    kernels.append(kernel)
    plt.plot(support, kernel, color="r")

sns.rugplot(x, color=".2", linewidth=3);

```

![http://seaborn.pydata.org/_images/distributions_14_0.png](img/31ee2d7a3dfda467565a2053ac19a38f.jpg)

W
wizardforcel 已提交
76
接下来,对这些曲线求和,计算支持网格(support grid)中每个点的密度值。然后对得到的曲线进行归一化,使曲线下的面积等于 1:
W
init  
wizardforcel 已提交
77 78 79 80 81 82 83 84 85 86 87

```py
from scipy.integrate import trapz
density = np.sum(kernels, axis=0)
density /= trapz(density, support)
plt.plot(support, density);

```

![http://seaborn.pydata.org/_images/distributions_16_0.png](img/d0ff3115fb5935fe56c1bb8123d5ddce.jpg)

W
wizardforcel 已提交
88
我们可以看到,如果在 seaborn 中使用[`kdeplot()`](../generated/seaborn.kdeplot.html#seaborn.kdeplot "seaborn.kdeplot") 函数, 我们可以得到相同的曲线。这个函数也被[`distplot()`](../generated/seaborn.distplot.html#seaborn.distplot "seaborn.distplot")所使用, 但是当您只想要密度估计时,它提供了一个更直接的接口,可以更容易地访问其他选项:
W
init  
wizardforcel 已提交
89 90 91 92 93 94 95 96

```py
sns.kdeplot(x, shade=True);

```

![http://seaborn.pydata.org/_images/distributions_18_0.png](img/247df80468d3edbc28836cb1cc56c81c.jpg)

W
wizardforcel 已提交
97
KDE 的带宽(`bw`)参数控制估计与数据的拟合程度,就像直方图中的 bin 大小一样。 它对应于我们在上面绘制的内核的宽度。 默认行为尝试使用常用参考规则猜测一个好的值,但尝试更大或更小的值可能会有所帮助:
W
init  
wizardforcel 已提交
98 99 100 101 102 103 104 105 106 107
```py
sns.kdeplot(x)
sns.kdeplot(x, bw=.2, label="bw: 0.2")
sns.kdeplot(x, bw=2, label="bw: 2")
plt.legend();

```

![http://seaborn.pydata.org/_images/distributions_20_0.png](img/8a713fe4da039acf9c3a4e70b274b60a.jpg)

W
wizardforcel 已提交
108
正如您在上面所看到的,高斯 KDE 过程的本质意味着估计超出了数据集中最大和最小的值。有可能控制超过极值多远的曲线是由'cut'参数绘制的;然而,这只影响曲线的绘制方式,而不影响曲线的拟合方式:
W
init  
wizardforcel 已提交
109 110 111 112 113 114 115 116 117

```py
sns.kdeplot(x, shade=True, cut=0)
sns.rugplot(x);

```

![http://seaborn.pydata.org/_images/distributions_22_0.png](img/63e498131614f726dd72a90161b58971.jpg)

A
alohahahaha 已提交
118
### 拟合参数分布
W
init  
wizardforcel 已提交
119

A
alohahahaha 已提交
120
您还可以使用 [`distplot()`](../generated/seaborn.distplot.html#seaborn.distplot "seaborn.distplot")
W
init  
wizardforcel 已提交
121

A
alohahahaha 已提交
122
将参数分布拟合到数据集上,并直观地评估其与观测数据的对应程度:
W
init  
wizardforcel 已提交
123 124 125 126 127 128 129 130
```py
x = np.random.gamma(6, size=200)
sns.distplot(x, kde=False, fit=stats.gamma);

```

![http://seaborn.pydata.org/_images/distributions_24_0.png](img/cf48dc45f5484db58f3d310e434b11a2.jpg)

A
alohahahaha 已提交
131
## 绘制二元分布
W
init  
wizardforcel 已提交
132

W
wizardforcel 已提交
133
它对于可视化两个变量的二元分布也很有用。在 seaborn 中,最简单的方法就是使用[`jointplot()`](../generated/seaborn.jointplot.html#seaborn.jointplot "seaborn.jointplot")函数,它创建了一个多面板图形,显示了两个变量之间的二元(或联合)关系,以及每个变量在单独轴上的一元(或边际)分布。
W
init  
wizardforcel 已提交
134 135 136 137 138 139 140 141

```py
mean, cov = [0, 1], [(1, .5), (.5, 1)]
data = np.random.multivariate_normal(mean, cov, 200)
df = pd.DataFrame(data, columns=["x", "y"])

```

A
alohahahaha 已提交
142
### 散点图
W
init  
wizardforcel 已提交
143

W
wizardforcel 已提交
144
可视化二元分布最常见的方法是散点图,其中每个观察点都以 _x_ 和 _y_ 值表示。 这类似于二维 rug plot。 您可以使用 matplotlib 的`plt.scatter` 函数绘制散点图, 它也是 [`jointplot()`](../generated/seaborn.jointplot.html#seaborn.jointplot "seaborn.jointplot")函数显示的默认类型的图:
W
init  
wizardforcel 已提交
145 146 147 148 149 150 151 152

```py
sns.jointplot(x="x", y="y", data=df);

```

![http://seaborn.pydata.org/_images/distributions_28_0.png](img/66ba868aeef60b82d90c872e188217ed.jpg)

A
alohahahaha 已提交
153
### 六边形“桶”(Hexbin)图
W
init  
wizardforcel 已提交
154

W
wizardforcel 已提交
155
类似于单变量的直方图,用于描绘二元变量关系的图称为 “hexbin” 图,因为它显示了落入六边形“桶”内的观察计数。 此图对于相对较大的数据集最有效。它可以通过调用 matplotlib 中的 `plt.hexbin`函数获得并且在[`jointplot()`](../generated/seaborn.jointplot.html#seaborn.jointplot "seaborn.jointplot")作为一种样式。当使用白色作为背景色时效果最佳。
W
init  
wizardforcel 已提交
156 157 158 159 160 161 162 163 164 165

```py
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");

```

![http://seaborn.pydata.org/_images/distributions_30_0.png](img/621cac508b507f43ba50f91290aea5fd.jpg)

A
alohahahaha 已提交
166
### 核密度估计
W
init  
wizardforcel 已提交
167

W
wizardforcel 已提交
168
也可以使用上面描述的核密度估计过程来可视化二元分布。在 seaborn 中,这种图用等高线图表示, 在[`jointplot()`](../generated/seaborn.jointplot.html#seaborn.jointplot "seaborn.jointplot")中被当作一种样式:
W
init  
wizardforcel 已提交
169 170 171 172 173 174 175 176

```py
sns.jointplot(x="x", y="y", data=df, kind="kde");

```

![http://seaborn.pydata.org/_images/distributions_32_0.png](img/3fa9b8716f00e81aa6ca6864cb110e2b.jpg)

W
wizardforcel 已提交
177
您还可以使用[`kdeplot()`](../generated/seaborn.kdeplot.html#seaborn.kdeplot "seaborn.kdeplot")函数绘制二维核密度图。这允许您在一个特定的(可能已经存在的)matplotlib 轴上绘制这种图,而 [`jointplot()`](../generated/seaborn.jointplot.html#seaborn.jointplot "seaborn.jointplot") 函数能够管理它自己的图:
W
init  
wizardforcel 已提交
178 179 180 181 182 183 184 185 186 187 188

```py
f, ax = plt.subplots(figsize=(6, 6))
sns.kdeplot(df.x, df.y, ax=ax)
sns.rugplot(df.x, color="g", ax=ax)
sns.rugplot(df.y, vertical=True, ax=ax);

```

![http://seaborn.pydata.org/_images/distributions_34_0.png](img/5bbf1afea90de1dcab11584fb0169efe.jpg)

A
alohahahaha 已提交
189
如果希望更连续地显示双变量密度,可以简单地增加轮廓层的数量:
W
init  
wizardforcel 已提交
190 191 192 193 194 195 196 197 198 199

```py
f, ax = plt.subplots(figsize=(6, 6))
cmap = sns.cubehelix_palette(as_cmap=True, dark=0, light=1, reverse=True)
sns.kdeplot(df.x, df.y, cmap=cmap, n_levels=60, shade=True);

```

![http://seaborn.pydata.org/_images/distributions_36_0.png](img/fd8b7fa16dccb291fe1a2148a45e3eba.jpg)

A
alohahahaha 已提交
200
[`jointplot()`](../generated/seaborn.jointplot.html#seaborn.jointplot "seaborn.jointplot")函数使用[`JointGrid`](../generated/seaborn.JointGrid.html#seaborn.JointGrid "seaborn.JointGrid")来管理图形。为了获得更大的灵活性,您可能想直接使用[`JointGrid`](../generated/seaborn.JointGrid.html#seaborn.JointGrid "seaborn.JointGrid")来绘制图形。[`jointplot()`](../generated/seaborn.jointplot.html#seaborn.jointplot "seaborn.jointplot")在绘图后返回[`JointGrid`](../generated/seaborn.JointGrid.html#seaborn.JointGrid "seaborn.JointGrid")对象,您可以使用它添加更多图层或调整可视化的其他方面:
W
init  
wizardforcel 已提交
201 202 203 204 205 206 207 208 209 210 211

```py
g = sns.jointplot(x="x", y="y", data=df, kind="kde", color="m")
g.plot_joint(plt.scatter, c="w", s=30, linewidth=1, marker="+")
g.ax_joint.collections[0].set_alpha(0)
g.set_axis_labels("$X$", "$Y$");

```

![http://seaborn.pydata.org/_images/distributions_38_0.png](img/aeaafccce597b72105feb6cf712b0ca2.jpg)

A
alohahahaha 已提交
212
## 可视化数据集中的成对关系
W
init  
wizardforcel 已提交
213

W
wizardforcel 已提交
214
要在数据集中绘制多个成对的双变量分布,您可以使用[`pairplot()`](../generated/seaborn.pairplot.html#seaborn.pairplot "seaborn.pairplot")函数。 这将创建一个轴矩阵并显示 DataFrame 中每对列的关系,默认情况下,它还绘制对角轴上每个变量的单变量分布:
W
init  
wizardforcel 已提交
215 216 217 218 219 220 221 222
```py
iris = sns.load_dataset("iris")
sns.pairplot(iris);

```

![http://seaborn.pydata.org/_images/distributions_40_0.png](img/bea67bf34fcd01d7b6f454ae5f563460.jpg)

A
alohahahaha 已提交
223
[`jointplot()`](../generated/seaborn.jointplot.html#seaborn.jointplot "seaborn.jointplot")[`JointGrid`](../generated/seaborn.JointGrid.html#seaborn.JointGrid "seaborn.JointGrid")之间的关系非常类似, [`pairplot()`](../generated/seaborn.pairplot.html#seaborn.pairplot "seaborn.pairplot")函数构建在[`PairGrid`](../generated/seaborn.PairGrid.html#seaborn.PairGrid "seaborn.PairGrid")对象之上, 可以直接使用它来获得更大的灵活性:
W
init  
wizardforcel 已提交
224 225 226 227 228 229 230 231

```py
g = sns.PairGrid(iris)
g.map_diag(sns.kdeplot)
g.map_offdiag(sns.kdeplot, n_levels=6);

```

A
alohahahaha 已提交
232
![http://seaborn.pydata.org/_images/distributions_42_0.png](img/c65d91122f8de69b16659df5ab31214e.jpg)