必备神器之seaborn

python绘图软件seaborn的常用介绍

官方文档: seaborn官方文档

以下是常用功能

import语句

1
import searborn as sns

第一章 艺术化的图表控制

Matplotlib无疑是高度可定制的,但快速实施出吸引人的细节就变得有些复杂。Seaborn作为一个带着定制主题和高级界面控制的Matplotlib扩展包,能让绘图变得更轻松,本部分主要介绍seaborn是如何对matplotlib输出的外观进行控制的。

1
2
3
4
5
6
%matplotlib inline 
#jupyter notebook 中的魔法函数,如果不是使用该软件请使用plt.show()用于显示图像
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
np.random.seed(sum(map(ord,"aesthetics"))) # 定义种子

定义一个含偏移的正弦图像,来比较传统的matplotlib和seaborn的不同:

1
2
3
4
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)

使用matplotlib默认设置的图形效果:

1
sinplot()

img

1
2
import seaborn as sns
sinplot()

img

seaborn默认的灰色网格底色灵感来源于matplotlib却更加柔和。大多数情况下,图应优于表。seaborn的默认灰色网格底色避免了刺目的干扰,对于多个方面的图形尤其有用,是一些更复杂的工具的核心。

Seaborn将matplotlib参数分成两个独立的组。第一组设定了美学风格,第二组则是不同的度量元素,这样就可以很容易地添加到代码当中了。

操作这些参数的接口是两对函数。为了控制样式,使用axesstyle()和setstyle()函数。为了扩展绘图,请使用plotting_context()和set_context()函数。在这两种情况下,第一个函数返回一个参数字典,第二个函数则设置matplotlib默认属性。

样式控制:axes_style() and set_style()

有5个seaborn的主题,适用于不同的应用和人群偏好:

  • darkgrid 黑色网格(默认)
  • whitegrid 白色网格
  • dark 黑色背景
  • white 白色背景
  • ticks 应该是四周都有刻度线的白背景?

网格能够帮助我们查找图表中的定量信息,而灰色网格主题中的白线能避免影响数据的表现,白色网格主题则类似的,当然更适合表达“重数据元素”(heavy data elements不理解)

1
2
3
sns.set_style("whitegrid")
data = np.random.normal(size=(20, 6)) + np.arange(6) / 2
sns.boxplot(data=data);

img

对于许多场景,(特别是对于像对话这样的设置,您主要想使用图形来提供数据模式的印象),网格就不那么必要了

1
2
sns.set_style("dark")
sinplot()

img

1
2
sns.set_style("white")
sinplot()

img

有时你可能想要给情节增加一点额外的结构,这就是ticks参数的用途:

1
2
3
sns.set_style("ticks")
sinplot()
# 官方的例子在上方/右方也拥有刻度线,而验证时却没有(是jupyter notebook的原因?)

img

这里是官方运行的结果,供参考:

img

特别的可以通过sns.axes_style(style=None, rc=None) 返回一个sns.set_style()可传的参数的字典

通过类似sns.set_style(“ticks”, {“xtick.major.size”: 8, “ytick.major.size”: 8})的方式写入更具体的配置样式。

关于sns.axes_style()下面会有说明和运行结果

用despine()进行边框控制

white和ticks参数的样式,都可以删除上方和右方坐标轴上不需要的边框,这在matplotlib中是无法通过参数实现的,却可以在seaborn中通过despine()函数轻松移除他们。

1
2
3
sns.set_style("white")
sinplot() # 默认无参数状态,就是删除上方和右方的边框
sns.despine()

img

一些图的边框可以通过数据移位,当然调用despine()也能做同样的事。当边框没有覆盖整个数据轴的范围的时候,trim参数会限制留存的边框范围。

1
2
3
f, ax = plt.subplots()
sns.violinplot(data=data)
sns.despine(offset=10, trim=True); # offset 两坐标轴离开距离;

img

你也可以通过往despine()中添加参数去控制边框

1
2
3
4
sns.set_style("whitegrid")
sns.boxplot(data=data, palette="deep")
sns.despine(left=True) # 删除左边边框
st = sns.axes_style("darkgrid")

img

despine(fig=None, ax=None, top=True, right=True, left=False, bottom=False, offset=None, trim=False)

从plot()函数中移除顶部或右边的边框

临时设定图形样式

虽然来回切换非常容易,但sns也允许用with语句中套用axes_style()达到临时设置参数的效果(仅对with块内的绘图函数起作用)。这也允许创建不同风格的坐标轴。

1
2
3
4
5
with sns.axes_style("darkgrid"):
plt.subplot(211)
sinplot()
plt.subplot(212)
sinplot(-1)

img

seaborn样式中最重要的元素

如果您想要定制seanborn的样式,可以将参数字典传递给axes_style()和set_style()的rc参数。注意,只能通过该方法覆盖样式定义的一部分参数。(然而,更高层次的set()函数接受任何matplotlib参数的字典)。

如果您想要查看包含哪些参数,您可以只调用该函数而不带参数,这将返回当前设置的字典:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
sns.axes_style()

{'axes.axisbelow': True,
'axes.edgecolor': 'white',
'axes.facecolor': '#EAEAF2',
'axes.grid': True,
'axes.labelcolor': '.15',
'axes.linewidth': 0.0,
'figure.facecolor': 'white',
'font.family': ['sans-serif'],
'font.sans-serif': ['Arial',
'Liberation Sans',
'Bitstream Vera Sans',
'sans-serif'],
'grid.color': 'white',
'grid.linestyle': '-',
'image.cmap': 'Greys',
'legend.frameon': False,
'legend.numpoints': 1,
'legend.scatterpoints': 1,
'lines.solid_capstyle': 'round',
'text.color': '.15',
'xtick.color': '.15',
'xtick.direction': 'out',
'xtick.major.size': 0.0,
'xtick.minor.size': 0.0,
'ytick.color': '.15',
'ytick.direction': 'out',
'ytick.major.size': 0.0,
'ytick.minor.size': 0.0}

或许,你可以试试不同种类的参数效果

1
2
sns.set_style("darkgrid", {"axes.facecolor": ".9"})
sinplot()

img

通过 plotting_context() 和 set_context() 调整绘图元素

另一组参数控制绘图元素的规模,这应该让您使用相同的代码来制作适合在较大或较小的情节适当的场景中使用的情节。

首先,可以通过sns.set()重置参数。

1
sns.set()

四种预设,按相对尺寸的顺序(线条越来越粗),分别是paper,notebook, talk, and poster。notebook的样式是默认的,上面的绘图都是使用默认的notebook预设。

1
2
3
sns.set_context("paper")
plt.figure(figsize=(8,6))
sinplot()

img

1
2
3
4
# default 默认设置
sns.set_context("notebook")
plt.figure(figsize=(8,6))
sinplot()

img

1
2
3
sns.set_context("talk")
plt.figure(figsize=(8,6))
sinplot()

img

1
2
3
sns.set_context("poster")
plt.figure(figsize=(8,6))
sinplot()

img

通过观察各种样式的结果,你应当可以了解context函数

类似的,还可以使用其中一个名称来调用set_context()来设置参数,您可以通过提供参数值的字典来覆盖参数。

通过更改context还可以独立地扩展字体元素的大小。(这个选项也可以通过顶级set()函数获得)。

1
2
sns.set_context("notebook", font_scale=1.5, rc={"lines.linewidth": 2.5})
sinplot()

img

类似地(尽管它可能用处不大),也可以使用with嵌套语句进行临时的设置。

样式和上下文都可以用set()函数快速地进行配置。这个函数还设置了默认的颜色选项,在下一节将详细介绍这一功能。


颜色显然比图形风格的其他方面都更加重要,因为颜色使用得当就可以有效显示或隐藏数据中的特征。有许多的好资源都可以了解关于在可视化中使用颜色的技巧,推荐Rob Simmon的《series of blog posts》和这篇进阶的技术文章,matplotlib文档现在也有一个很好的教程,说明了如何在内置色彩映射中构建的一些感知特性。

Seaborn让你更容易选择和使用那些适合你数据和视觉的颜色。

1
2
3
4
5
6
%matplotlib inline
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(rc={"figure.figsize": (6, 6)})
np.random.seed(sum(map(ord, "palettes")))

通过color_palette()创建调色板

最重要的直接设置调色板的函数就是color_palette()。这个函数提供了许多(并非所有)在seaborn内生成颜色的方式。并且它可以用于任何函数内部的palette参数设置(在某些情况下当需要多种颜色时也可以传入到color参数)

color_palette()允许任意的seaborn调色板或matplotlib的颜色映射(除了jet,你应该完全不使用它)。它还可以使用任何有效的matplotlib格式指定的颜色列表(RGB元组、十六进制颜色代码或HTML颜色名称)。返回值总是一个RGB元组的列表。

最后,直接调用没有传入参数的color_palette()将返回默认的颜色循环。

对应的函数set_palette()接受相同的参数,并为所有图设置默认的颜色循环。你也可以在with块中使用color_palette()来实现临时的更改调色板配置(下面有详细例子)。

通常在不知道数据的具体特征的情况下不可能知道什么类型的调色板或颜色映射对于一组数据来说是最好的。因此,我们将用三种不同类型的调色板:分类色板、连续色板和离散色板,来区分和使用color_palette()函数。

分类色板

分类色板(定性)是在区分没有固定顺序的数据时最好的选择。

在导入seaborn库后,默认的颜色循环被更改为一组六种颜色。虽然这些颜色可能会让你想起matplotlib的标准颜色循环,但他们无疑更赏心悦目一些。

1
2
current_palette = sns.color_palette()
sns.palplot(current_palette)

img

默认颜色主题共有六种不同的变化分别是:deep, muted, pastel, bright, dark, 和 colorblind。类似下面的方式直接传入即可。

1
2
current_palette = sns.color_palette("dark") # 直接传入对应的参数即可变化
sns.palplot(current_palette)

img

使用圆形颜色系统

当你有六个以上的分类要区分时,最简单的方法就是在一个圆形的颜色空间中画出均匀间隔的颜色(这样的色调会保持亮度和饱和度不变)。这是大多数的当他们需要使用比当前默认颜色循环中设置的颜色更多时的默认方案。

最常用的方法是使用hls的颜色空间,这是RGB值的一个简单转换。

1
sns.palplot(sns.color_palette("hls", 8))

img

当然,也可以使用hls_palette()函数来控制颜色的亮度和饱和。

1
2
sns.palplot(sns.hls_palette(8, l=.3, s=.8))
# l-亮度 lightness / s-饱和 saturation

img

由于人类视觉系统的工作方式,会导致在RGB度量上强度一致的颜色在视觉中并不平衡。比如,我们黄色和绿色是相对较亮的颜色,而蓝色则相对较暗,使得这可能会成为与hls系统一致的一个问题。

为了解决这一问题,seaborn为husl系统提供了一个接口,这也使得选择均匀间隔的色彩变得更加容易,同时保持亮度和饱和度更加一致。

1
sns.palplot(sns.color_palette("husl", 8))

img

使用分类颜色调色板

另一种视觉上令人愉悦的分类调色板来自于Color Brewer工具(它也有连续调色板和离散调色板,我们将在下面的图中看到)。这些也存在于matplotlib颜色映射中,但是它们没有得到适当的处理。在这里,当你要求一个定性颜色的调色板时,你总是会得到离散的颜色,但这意味着在某一点它们会开始循环。

Color Brewer工具的一个很好的特点是,它提供了一些关于调色板是色盲安全的指导。有各种各样的适合色盲的颜色,但是最常见的变异导致很难区分红色和绿色。一般来说,避免使用红色和绿色来表示颜色以区分元素是一个不错的主意。

1
sns.palplot(sns.color_palette("Paired"))

img

1
sns.palplot(sns.color_palette("Set2", 10))

img

为了帮助您从Color Brewer工具中选择调色板,这里有choose_colorbrewer_palette()函数。这个函数必须在IPython notebook中使用,它将启动一个交互式小部件,让您浏览各种选项并调整参数。

当然,您可能只想使用一组您特别喜欢的颜色。因为color_palette()接受一个颜色列表,这很容易做到。

1
2
3
4
5
6
flatui = ["#9b59b6", "#3498db", "#95a5a6", "#e74c3c", "#34495e", "#2ecc71"]
sns.palplot(sns.color_palette(flatui))
sns.choose_colorbrewer_palette("sequential")
# data_type: {‘sequential’, ‘diverging’, ‘qualitative’}
sns.choose_colorbrewer_palette("sequential",as_cmap=True)
# as_cmap参数用来更改显示的颜色范围是离散的还是连续的

img

img

img

使用xkcd颜色来命名颜色

xkcd包含了一套众包努力的针对随机RGB色的命名。产生了954个可以随时通过xdcd_rgb字典中调用的命名颜色。

1
2
3
plt.plot([0, 1], [0, 1], sns.xkcd_rgb["pale red"], lw=3)
plt.plot([0, 1], [0, 2], sns.xkcd_rgb["medium green"], lw=3)
plt.plot([0, 1], [0, 3], sns.xkcd_rgb["denim blue"], lw=3);

img

如果你想花一些时间挑选颜色,或许这种交互式的可视化(官方链接失效)是非常有帮助的。除了将单一颜色从xkcd_rgb字典中取出,也可以通过名称列表传入xkcd_palette()函数中取得颜色组。

1
2
colors = ["windows blue", "amber", "greyish", "faded green", "dusty purple"]
sns.palplot(sns.xkcd_palette(colors))

img

连续色板

调色板中第二大类称为“顺序”。这种颜色映射对应的是从相对低价值(无意义)数据到高价值(有意义)的数据范围。虽然有时候你会需要一个连续的离散颜色调色板,用他们像kdeplot()或者corrplot()功能映射更加常见(以及可能类似的matplotlib功能)。

非常可能的是见到jet色彩映射(或其他采用调色板)在这种情况下使用,因为色彩范围提供有关数据的附加信息。然而,打的色调变化中往往会引入不连续性中不存在的数据和视觉系统不能自然的通过“彩虹色”定量产生“高”、“低”之分。其结果是,这样的可视化更像是一个谜题,模糊了数据中的信息而并非揭示这种信息。事实上,jet调色板可能非常糟糕,因为最亮的颜色,黄色和青色用于显示中间数值,这就导致强调了一些没有意义的数据而忽视了端点的数据。

所以对于连续的数据,最好是使用那些在色调上相对细微变化的调色板,同时在亮度和饱和度上有很大的变化。这种方法将自然地吸引数据中相对重要的部分

Color Brewer的字典中就有一组很好的调色板。它们是以在调色板中的主导颜色(或颜色)命名的。

1
sns.palplot(sns.color_palette("Blues"))

img

就像在matplotlib中一样,如果您想要翻转渐变,您可以在面板名称中添加一个_r后缀。

1
sns.palplot(sns.color_palette("BuGn_r"))

img

seaborn还增加了一个允许创建没有动态范围的”dark”面板。如果你想按顺序画线或点,这可能是有用的,因为颜色鲜艳的线可能很难区分。

类似的,这种暗处理的颜色,需要在面板名称中添加一个_d后缀

1
sns.palplot(sns.color_palette("GnBu_d"))

img

牢记,你可能想使用choose_colorbrewer_palette()函数取绘制各种不同的选项。如果你想返回一个变量当做颜色映射传入seaborn或matplotlib的函数中,可以设置as_cmap参数为True。

cubehelix_palette()函数的连续调色板

cubehelix调色板系统具有线性增加或降低亮度和色调变化顺序的调色板。这意味着在你的映射信息会在保存为黑色和白色(为印刷)时或被一个色盲的人浏览时可以得以保留。

Matplotlib拥有一个默认的内置cubehelix版本可供创建:

1
sns.palplot(sns.color_palette("cubehelix", 8))

img

seaborn为cubehelix系统添加一个接口使得其可以在各种变化中都保持良好的亮度线性梯度。

通过seaborn的cubehelix_palette()函数返回的调色板与matplotlib默认值稍有所不同,它不会在色轮周围旋转或覆盖更广的强度范围。seaborn还改变了排序使得更重要的值显得更暗:

1
sns.palplot(sns.cubehelix_palette(8))

img

其他cubehelix_palette()的参数主要调整色板的视觉。两个重要的选择是:start(值的范围为03)和rot,还有rot的次数(-11之间的任意值)

1
sns.palplot(sns.cubehelix_palette(8, start=.5, rot=-.75))

img

你也可以控制断点的亮度和甚至对调结果顺序

1
sns.palplot(sns.cubehelix_palette(8, start=2, rot=0, dark=0, light=.95, reverse=True))

img

默认情况下你只会得到一些与seaborn调色板相似的颜色的列表,但你也可以让调色板返回一个可以用as_cmap=True传入seaborn或matplotlib函数的颜色映射对象

1
2
3
x, y = np.random.multivariate_normal([0, 0], [[1, -.5], [-.5, 1]], size=300).T
cmap = sns.cubehelix_palette(light=1, as_cmap=True)
sns.kdeplot(x, y, cmap=cmap, shade=True);

img

类似的,也可以在notebook中使用choose_cubehelix_palette()函数启动一个互助程序来帮助选择更适合的调色板或颜色映射。如果想让函数返回一个类似hexbin的颜色映射而非一个列表则需要传入as_cmap=True。

使用light_palette() 和dark_palette()调用定制连续调色板

这里还有一个更简单的连续调色板的使用方式,就是调用light_palette() 和dark_palette(),这与一个单一颜色和种子产生的从亮到暗的饱和度的调色板。这些函数还伴有choose_light_palette() and choose_dark_palette()函数,这些函数启动了交互式小部件来创建这些调色板。

1
2
sns.palplot(sns.light_palette("green"))
sns.palplot(sns.dark_palette("purple"))

img

img

这些调色板结果也可以颠倒

1
sns.palplot(sns.light_palette("navy", reverse=True))

img

当然也可以创建一个颜色映射对象取代颜色列表

1
2
pal = sns.dark_palette("palegreen", as_cmap=True)
sns.kdeplot(x, y, cmap=pal);

img

默认情况下,任何有效的matplotlib颜色可以传递给input参数。也可以在hls或husl空间中提供默认的rgb元组,您还可以使用任何有效的xkcd颜色的种子。

1
2
sns.palplot(sns.light_palette((210, 90, 60), input="husl"))
sns.palplot(sns.dark_palette("muted purple", input="xkcd"))

img

img

需要注意的是,为默认的input空间提供交互的组件是husl,这与函数自身默认的并不同,但这在背景下却是更有用的。

离散色板

调色板中的第三类被称为“离散”。用于可能无论大的低的值和大的高的值都非常重要的数据。数据中通常有一个定义良好的中点。例如,如果你正在绘制温度变化从基线值,最好使用不同色图显示相对降低和相对增加面积的地区。

选择离散色板的规则类似于顺序色板,除了你想满足一个强调的颜色中点以及用不同起始颜色的两个相对微妙的变化。同样重要的是,起始值的亮度和饱和度是相同的。

同样重要的是要强调,应该避免使用红色和绿色,因为大量的潜在观众将无法分辨它们。

你不应该感到惊讶的是,Color Brewer颜色字典里拥有一套精心挑选的离散颜色映射:

1
2
sns.palplot(sns.color_palette("BrBG", 7))
sns.palplot(sns.color_palette("RdBu_r", 7))

img

img

另一个在matplotlib中建立的明智的选择是coolwarm面板。请注意,这个颜色映射在中间值和极端之间并没有太大的对比。

1
sns.palplot(sns.color_palette("coolwarm", 7))

img

用diverging_palette()使用定制离散色板

你也可以使用海运功能diverging_palette()为离散的数据创建一个定制的颜色映射。(当然也有一个类似配套的互动工具:choose_diverging_palette())。该函数使用husl颜色系统的离散色板。你需随意传递两种颜色,并设定明度和饱和度的端点。函数将使用husl的端点值及由此产生的中间值进行均衡。

1
2
sns.palplot(sns.diverging_palette(220, 20, n=7))
sns.palplot(sns.diverging_palette(145, 280, s=85, l=25, n=7))

img

img

sep参数控制面板中间区域的两个渐变的宽度。

1
sns.palplot(sns.diverging_palette(10, 220, sep=80, n=7))

img

也可以用中间的色调来选择调色,而不是用亮度

1
sns.palplot(sns.diverging_palette(255, 133, l=60, n=7, center="dark"))

img

用set_palette()更改色变的默认值

color_palette() 函数有一个名为set_palette()的配套。它们之间的关系类似于在美学教程中涉及的aesthetics tutorial. set_palette()。set_palette()接受与color_palette()相同的参数,但是它会更改默认的matplotlib参数,以便成为所有的调色板配置。

1
2
3
4
5
6
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_palette("husl")
sinplot()

img

color_palette()函数也可以在一个with块中使用,以达到临时更改调色板的目的

1
2
with sns.color_palette("PuBuGn_d"):
sinplot()

img

简单常用色彩总结:

  • 分类:hls husl Paired Set1~Set3(色调不同)
  • 连续:Blues[蓝s,颜色+s] BuGn[蓝绿] cubehelix(同色系渐变)
  • 离散:BrBG[棕绿] RdBu[红蓝] coolwarm[冷暖](双色对称)

本章后记

这章内容确认让对色彩与不同数据形式的图像之间的关系有了新的认识,恐怕色让图形好看和更有格调仅仅只是初级阶段。然而文中涉及了大量的色彩专用的名词和理论,只能不求甚解的翻出来强行理解了,谬误在所难免,欢迎各位大神指正,万分感谢!

第三章 分布数据集的可视化

在处理一组数据时,通常首先要做的是了解变量是如何分布的。这一章将简要介绍seborn中用于检查单变量和双变量分布的一些工具。你可能还想看看分类变量的章节,来看看函数的例子,这些函数让我们很容易比较变量的分布。

1
2
3
4
5
6
7
8
9
10
%matplotlib inline
import numpy as np
import pandas as pd
from scipy import stats, integrate
import matplotlib.pyplot as plt

import seaborn as sns
sns.set(color_codes=True)

np.random.seed(sum(map(ord, "distributions")))

单变量分布

最方便的方式是快速查看单变量分布无疑是使用distplot()函数。默认情况下,这将绘制一个直方图,并拟合出核密度估计(KDE)。

1
2
x = np.random.normal(size=100)
sns.distplot(x);

img

直方图

直方图应当是非常熟悉的函数了,在matplotlib中就存在hist函数。直方图通过在数据的范围内切成数据片段,然后绘制每个数据片段中的观察次数,来表示整体数据的分布。

为了说明这一点,我们删除密度曲线并添加了地毯图,每个观察点绘制一个小的垂直刻度。您可以使用rugplot()函数来制作地毯图,但它也可以在distplot()中使用:

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

img

绘制直方图时,主要的选择是使用切分数据片段的数量或在何位置切分数据片段。 distplot()使用一个简单的规则来很好地猜测并给予默认的切分数量,但尝试更多或更少的数据片段可能会显示出数据中的其他特征:

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

img

核密度估计(KDE) Kernel density estimaton

或许你对核密度估计可能不像直方图那么熟悉,但它是绘制分布形状的有力工具。如同直方图一样,KDE图会对一个轴上的另一轴的高度的观测密度进行描述:

1
sns.distplot(x, hist=False, rug=True);

img

绘制KDE比绘制直方图更有计算性。所发生的是,每一个观察都被一个以这个值为中心的正态( 高斯)曲线所取代。

1
2
3
4
5
6
7
8
9
10
11
12
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);

img

接下来,这些曲线可以用来计算支持网格中每个点的密度值。得到的曲线再用归一化使得它下面的面积等于1:

1
2
3
density = np.sum(kernels, axis=0)
density /= integrate.trapz(density, support)
plt.plot(support, density);

img

我们可以看到,如果我们在seaborn中使用kdeplot()函数,我们得到相同的曲线。 这个函数由distplot()使用,但是当您只想要密度估计时,它提供了一个更直接的界面,更容易访问其他选项:

1
sns.kdeplot(x, shade=True);

img

KDE的带宽bandwidth(bw)参数控制估计对数据的拟合程度,与直方图中的bin(数据切分数量参数)大小非常相似。 它对应于我们上面绘制的内核的宽度。 默认中会尝试使用通用引用规则猜测一个适合的值,但尝试更大或更小的值可能会有所帮助:

1
2
3
4
sns.kdeplot(x)
sns.kdeplot(x, bw=.2, label="bw: 0.2")
sns.kdeplot(x, bw=2, label="bw: 2")
plt.legend();

img

如上所述,高斯KDE过程的性质意味着估计延续了数据集中最大和最小的值。 可以通过cut参数来控制绘制曲线的极值值的距离; 然而,这只影响曲线的绘制方式,而不是曲线如何拟合:

1
2
sns.kdeplot(x, shade=True, cut=0)
sns.rugplot(x);

img

拟合参数分布

还可以使用distplot()将参数分布拟合到数据集,并可视化地评估其与观察数据的对应关系:

1
2
x = np.random.gamma(6, size=200)
sns.distplot(x, kde=False, fit=stats.gamma);

img

绘制双变量分布

在绘制两个变量的双变量分布也是有用的。在seaborn中这样做的最简单的方法就是在jointplot()函数中创建一个多面板数字,显示两个变量之间的双变量(或联合)关系以及每个变量的单变量(或边际)分布和轴。

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

img

散点图

双变量分布的最熟悉的可视化方式无疑是散点图,其中每个观察结果以x和y值表示。这是两个方面的地毯图。可以使用matplotlib中的plt.scatter函数绘制散点图,它也是jointplot()函数显示的默认方式。

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

HexBin图

直方图的双变量类似物被称为“hexbin”图,因为它显示了落在六边形仓内的观测数。该图适用于较大的数据集。通过matplotlib plt.hexbin函数和jointplot()中的样式可以实现。 它最好使用白色背景:

1
2
3
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");

img

核密度估计

使用上述内核密度估计程序可视化双变量分布也是可行的。在seaborn中,这种图用等高线图显示,可以在jointplot()中作为样式传入参数使用:

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

img

还可以使用kdeplot()函数绘制二维核密度图。这样可以将这种绘图绘制到一个特定的(可能已经存在的)matplotlib轴上,而jointplot()函数只能管理自己:

1
2
3
4
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);

img

如果是希望更连续地显示双变量密度,您可以简单地增加n_levels参数增加轮廓级数:

1
2
3
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);

img

jointplot()函数使用JointGrid来管理。为了获得更多的灵活性,您可能需要直接使用JointGrid绘制图形。jointplot()在绘制后返回JointGrid对象,您可以使用它来添加更多图层或调整可视化的其他方面:

1
2
3
4
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$");

img

呈现数据集中成对的关系

要在数据集中绘制多个成对双变量分布,可以使用pairplot()函数。这将创建一个轴的矩阵,并显示DataFrame中每对列的关系。默认情况下,它也绘制每个变量在对角轴上的单变量:

1
2
iris = sns.load_dataset("iris")
sns.pairplot(iris);

img

对于jointplot()和JointGrid之间的关系,pairplot()函数是建立在一个PairGrid对象上的,可以直接使用它来获得更大的灵活性:

1
2
3
g = sns.PairGrid(iris)
g.map_diag(sns.kdeplot)
g.map_offdiag(sns.kdeplot, cmap="Blues_d", n_levels=6);

img

这章介绍的针对回归类型的散点数据的可视化可能是未来机器学习最直接的助理,这章给我的感悟很多。

许多数据集包含多个定量变量,分析的目的通常是将这些变量相互关联起来。 我们以前讨论过可以通过显示两个变量的联合分布来实现的功能。 然而,使用统计模型来估计两个噪声观测组之间的简单关系可能是非常有帮助的。 本章讨论的功能将通过线性回归的通用框架进行。

在Tukey的精神中,Seaborn的回归图主要是为了添加一个视觉指南,有助于在探索性数据分析期间强调数据集中的模式。 也就是说,Seaborn本身并不是统计分析的一揽子计划。 要获得与回归模型拟合相关的量化措施,您应该使用statsmodels。 然而,Seaborn的目标是通过可视化快速,轻松地探索数据集,使之变得与通过统计表格来探索数据集一样重要(如果不是更重要的话)。

1
2
3
4
5
6
7
8
9
10
11
12
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt

import seaborn as sns
sns.set(color_codes=True)

np.random.seed(sum(map(ord, "regression")))

tips = sns.load_dataset("tips")

绘制线性回归模型的函数

使用Seaborn中的两个主要功能可视化通过回归确定的线性关系。这些函数regplot()和lmplot()是密切相关的,并且共享了大部分的核心功能。然而,了解他们不同的方式很重要,以便您可以快速为特定工作选择正确的工具。

在最简单的调用中,两个函数绘制了两个变量x和y的散点图,然后拟合回归模型y〜x并绘制了该回归线的结果回归线和95%置信区间:

1
sns.regplot(x="total_bill", y="tip", data=tips);

img

1
sns.lmplot(x="total_bill", y="tip", data=tips);

img

很显然,所得到的的图的结果是相同的,除了图形形状略有些不同,这里会简短的解释。

目前,要知道的另一个主要区别是regplot()以各种格式接受x和y变量,包括numpy数组、Pandas的Series列或DataFrame对象的变量引用;不一样的是,lmplot()将数据集作为一个必需的参数,而x和y变量必须指定为字符串。这种数据格式称为“长格式”或“整洁”数据。除了这种输入灵活性,regplot()可以看做是拥有lmplot()特征的子集,所以后面将使用后者进行演示。

备注:

这里官方的例子实际上并不好,比较容易的理解方式是:上面的结果可以在regplot()函数中通过只传入x和y绘出:sns.regplot(x=tips[“total_bill”], y=tips[“tip”]);而相应的sns.lmplot(x=tips[“total_bill”], y=tips[“tip”])这种写法就会报错,因为数据集data是lmplot()的必传参数。

当其中一个变量取值为离散型的时候,可以拟合一个线性回归。然而,这种数据集生成的简单散点图通常不是最优的:

1
2
3
4
5
6
7
8
9
tips.head()

total_bill tip sex smoker day time size big_tip
0 16.99 1.01 Female No Sun Dinner 2 False
1 10.34 1.66 Male No Sun Dinner 3 True
2 21.01 3.50 Male No Sun Dinner 3 True
3 23.68 3.31 Male No Sun Dinner 2 False
4 24.59 3.61 Female No Sun Dinner 4 False
sns.lmplot(data=tips,x="size",y="tip")

img

一个常用的方法是为离散值添加一些随机噪声的“抖动”(jitter),使得这些值的分布更加明晰。

值得注意的是,抖动仅适用于散点图数据,且不会影响拟合的回归线本身

1
sns.lmplot(x="size", y="tip", data=tips, x_jitter=.05);

img

另一种选择是在每个独立的数据分组中对观察结果进行折叠,以绘制中心趋势的估计以及置信区间:

1
sns.lmplot(x="size", y="tip", data=tips, x_estimator=np.mean);

img

不同类型的模型拟合

上面使用的简单线性回归模型非常简单,但是,它不适用于某些种类的数据集。 Anscombe’s quartet数据集显示了一些简单线性回归提供了简单目视检查清楚显示差异的关系估计的例子。 例如,在第一种情况下,线性回归是一个很好的模型:

1
2
3
anscombe = sns.load_dataset("anscombe")
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'I'"),
ci=None, scatter_kws={"s": 80});

img

第二个数据集中的线性关系是一样的,但是基本清楚地表明这不是一个好的模型:

1
2
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'II'"),
ci=None, scatter_kws={"s": 80});

img

在存在这些高阶关系的情况下,lmplot()和regplot()可以拟合多项式回归模型来拟合数据集中的简单类型的非线性趋势:

1
2
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'II'"),
order=2, ci=None, scatter_kws={"s": 80});

img

除了正在研究的主要关系之外,“异常值”观察还有一个不同的问题,它们由于某种原因而偏离了主要关系:

1
2
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'III'"),
ci=None, scatter_kws={"s": 80});

img

在有异常值的情况下,它可以使用不同的损失函数来减小相对较大的残差,拟合一个健壮的回归模型,传入robust=True:

1
2
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'III'"),
robust=True, ci=None, scatter_kws={"s": 80});

img

当y变量是二进制时,简单的线性回归也“工作”了,但提供了不可信的预测结果:

1
2
3
tips["big_tip"] = (tips.tip / tips.total_bill) > .15
sns.lmplot(x="total_bill", y="big_tip", data=tips,
y_jitter=.03);

img

在这种情况下,解决方案是拟合逻辑(Logistic)回归,使得回归线显示给定值x的y=1的估计概率:

1
2
sns.lmplot(x="total_bill", y="big_tip", data=tips,
logistic=True, y_jitter=.03);

img

请注意,逻辑回归估计比简单回归计算密集程度(Robust回归也是如此),并且由于使用引导程序计算回归线周围的置信区间,您可能希望将其关闭获得更快的迭代速度(使用参数ci=None)。

一个完全不同的方法是使用一个lowess smoother拟合非参数回归。 这种方法具有最少的假设,尽管它是计算密集型的,因此目前根本不计算置信区间:

1
2
sns.lmplot(x="total_bill", y="tip", data=tips,
lowess=True);

img

residplot()是一个有用的工具,用于检查简单的回归模型是否拟合数据集。它拟合并移除一个简单的线性回归,然后绘制每个观察值的残差值。 理想情况下,这些值应随机散布在y = 0附近:

1
2
sns.residplot(x="x", y="y", data=anscombe.query("dataset == 'I'"),
scatter_kws={"s": 80});

img

如果残差中有结构,则表明简单的线性回归是不合适的:

1
2
sns.residplot(x="x", y="y", data=anscombe.query("dataset == 'II'"),
scatter_kws={"s": 80});

img

调节其他变量

上面的图表显示了许多方法来探索一对变量之间的关系。然而,通常,一个更有趣的问题是“这两个变量之间的关系如何作为第三个变量的函数而变化?”这是regplot()和lmplot()之间的区别。 虽然regplot()总是显示单个关系,lmplot()将regplot()与FacetGrid结合在一起,提供了一个简单的界面,可以在“faceted”图上显示线性回归,从而允许您探索与多达三个其他类别变量的交互。

分类关系的最佳方式是绘制相同轴上的两个级别,并使用颜色来区分它们:

1
sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips);

img

除了颜色之外,还可以使用不同的散点图标记来使黑色和白色的图像更好地绘制。 您还可以完全控制所用的颜色:

1
2
sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips,
markers=["o", "x"], palette="Set1");

img

要添加另一个变量,您可以绘制多个“facet”,每个级别的变量出现在网格的行或列中:

1
sns.lmplot(x="total_bill", y="tip", hue="smoker", col="time", data=tips);

img

1
2
sns.lmplot(x="total_bill", y="tip", hue="smoker",
col="time", row="sex", data=tips);

img

控制绘制的大小和形状

在我们注意到由regplot()和lmplot()创建的默认绘图看起来是一样的,但在轴上却具有不同大小和形状。 这是因为func:regplot是一个“轴级”功能绘制到特定的轴上。 这意味着您可以自己制作多面板图形,并精确控制回归图的位置。 如果没有提供轴,它只需使用“当前活动的”轴,这就是为什么默认绘图与大多数其他matplotlib函数具有相同的大小和形状的原因。要控制大小,您需要自己创建一个图形对象。

1
2
f, ax = plt.subplots(figsize=(5, 6))
sns.regplot(x="total_bill", y="tip", data=tips, ax=ax);

img

相反,lmplot()图的大小和形状通过FacetGrid界面使用size和aspect参数进行控制,这些参数适用于每个图中的设置,而不是整体图形:

1
2
sns.lmplot(x="total_bill", y="tip", col="day", data=tips,
col_wrap=2, size=3);

img

1
2
sns.lmplot(x="total_bill", y="tip", col="day", data=tips,
aspect=.5);

img

在其他背景下绘制回归

另外一些Seaborn函数在更大,更复杂的绘制中使用regplot()。 第一个是在上一章分布介绍的jointplot()函数。 除了前面讨论的绘图样式之外,jointplot()可以使用regplot()通过传递kind =”reg”来显示关节轴上的线性回归拟合:

1
sns.jointplot(x="total_bill", y="tip", data=tips, kind="reg");

img

使用kind=”reg”的pairplot()函数结合了regplot()和PairGrid来显示数据集中变量之间的线性关系。 注意这是不同于lmplot()的。 在下图中,两轴在第三个变量的两个级别上不显示相同的关系; 相反,PairGrid()用于显示数据集中变量的不同配对之间的多个关系:

1
2
sns.pairplot(tips, x_vars=["total_bill", "size"], y_vars=["tip"],
size=5, aspect=.8, kind="reg");

img

类似lmplot(),但不同于jointplot(),使用hue参数在pairplot()中内置了一个附加分类变量的条件:

1
2
sns.pairplot(tips, x_vars=["total_bill", "size"], y_vars=["tip"],
hue="smoker", size=5, aspect=.8, kind="reg");

img

第五章 分类数据的绘制

我们之前探讨了如何使用散点图和回归模型拟合来可视化两个变量之间的关系,以及如何在其他分类变量的层次之间进行展示。 当然,还有一大类问题就是分类数据的问题了? 在这种情况下,散点图和回归模型方法将不起作用。当然,有几个观察可视化这种关系的选择,我们将在本章中讨论。

非常实用的方法是将Seaborn的分类图分为三类,将分类变量每个级别的每个观察结果显示出来,显示每个观察分布的抽象表示,以及应用统计估计显示的权重趋势和置信区间:

  • 第一个包括函数swarmplot()和stripplot()
  • 第二个包括函数boxplot()和violinplot()
  • 第三个包括函数barplot()和pointplt()

在了解他们如何接受数据传入方面,尽管每个参数都聚有控制应用于该数据可视化细节的特定参数,但这些功能都共享一个基本的API。

这与之前的regplot()和lmplot()的关系非常相似(未禾备注:在seaborn的构架中很容易分成这样两类用途相似,使用有所差异的替代方案函数)。在Seaborn中,相对低级别和相对高级别的方法用于定制分类数据的绘制图,上面列出的函数都是低级别的,他们绘制在特定的matplotlib轴上。还有更高级别的factorplot()(未禾备注:这是一个非常简明的快速绘制函数,具体用法会在最后有详细介绍),它将这些功能与FacetGrid结合,以便在面板的网格中应用分类图像。

使用“整洁”格式的DataFrame调用这些函数是最简单和最好的,尽管较低级别的函数也接受宽形式的DataFrames或简单的观察向量。见下面的例子。

未禾备注:你甚至可以理解为这一章都是在具体学习factorplot()函数,快速、直接、功能强大的绘图函数谁不爱?

1
2
3
4
5
6
7
8
9
10
11
12
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="whitegrid", color_codes=True)

np.random.seed(sum(map(ord, "categorical")))
titanic = sns.load_dataset("titanic")
tips = sns.load_dataset("tips")
iris = sns.load_dataset("iris")

分类散点图

显示分类变量级别中某些定量变量的值的一种简单方法使用stripplot(),它会将分散图概括为其中一个变量是分类的:

1
sns.stripplot(x="day", y="total_bill", data=tips);

img

在条纹图中,散点图通常将重叠。这使得很难看到数据的完整分布。一个简单的解决方案是使用一些随机的“抖动”调整位置(仅沿着分类轴)

未禾备注:抖动是平时可视化中的常用的观察“密度”的方法,除了使用参数抖动,特定的抖动需求也可以用numpy在数据上处理实现

1
sns.stripplot(x="day", y="total_bill", data=tips, jitter=True);

img

不同的方法是使用函数swarmplot(),它使用避免重叠点的算法将分类轴上的每个散点图点定位:

未禾备注:道理上,即使抖动还是会有重叠的可能,所以这种方法可能更好

1
sns.swarmplot(x="day", y="total_bill", data=tips);

img

当然也可以传入hue参数添加多个嵌套的分类变量。高于分类轴上的颜色和位置时冗余的,现在每个都提供有两个变量之一的信息:

1
sns.swarmplot(x="day", y="total_bill", hue="sex",data=tips);

img

一般来说,Seaborn分类绘图功能试图从数据中推断类别的顺序。 如果您的数据有一个pandas分类数据类型,那么类别的默认顺序可以在那里设置。 对于其他数据类型,字符串类型的类别将按照它们在DataFrame中显示的顺序进行绘制,但是数组类别将被排序:

1
sns.swarmplot(x="size", y="total_bill", data=tips);

img

使用这些图,将分类变量放在垂直轴上是非常有用的(当类别名称相对较长或有很多类别时,这一点特别有用)。 您可以使用orient关键字强制定向,但通常可以从传递给x和/或y的变量的数据类型推断绘图方向:

1
sns.swarmplot(x="total_bill", y="day", hue="time", data=tips);

img

分类内的观测分布

分类散点图固然简单实用,但在某些特定的的情况下,他们可以提供的值的分布信息会变得及其有限(并不明晰)。 有几种方式可以方便的解决这个问题,在类别之间进行简单比较并汇总信息,我们快速讨论并比较一些适合这类数据观测的函数。

箱线图

第一个是熟悉的boxplot()。这种图形显示了分布的三个四分位值与极值。“晶须”延伸到低于和低四分位数的1.5 IQR内的点,然后独立显示落在该范围之外的观测值。 重要的是,这意味着boxplot中的每个值的显示都对应于数据中的实际观察值:

未禾备注:IQR即统计学概念四分位距,第一四分位与第三四分位之间的距离,具体内容请参考更深入的相关资料

1
sns.boxplot(x="day", y="total_bill", hue="time", data=tips);

img

提琴图

不同的方法是一个violinplot(),它结合了箱体图和分布教程中描述的核心密度估计过程:

未禾备注:核密度估计,即全文中提到的,或参数内传入的kde,具体概念内容请参考相关文档

1
sns.violinplot(x="total_bill", y="day", hue="time", data=tips);

img

这种方法使用核密度估计来更好地描述值的分布。此外,小提琴内还显示了箱体四分位数和晶须值。由于小提琴使用KDE,还有一些其他可以调整的参数,相对于简单的boxplot增加了一些复杂性:

1
2
sns.violinplot(x="total_bill", y="day", hue="time", data=tips,
bw=.1, scale="count", scale_hue=False);

img

当色调参数只有两个级别时,也可以传入参数split至violinplot(),这样可以更有效地利用空间:

1
sns.violinplot(x="day", y="total_bill", hue="sex", data=tips, split=True);

img

最后,在绘制提琴图的时候有几个选项,包括显示每个人的观察结果而不是总结框图值的方法:

1
2
sns.violinplot(x="day", y="total_bill", hue="sex", data=tips,
split=True, inner="stick", palette="Set3");

img

将swarmplot()或者swarmplot()与violinplot()或boxplot()结合使用可以显示每个观察结果以及分布的摘要:

未禾备注:说实话,并不推荐这么做,过多的信息除了炫技没有什么实际用处。

1
2
sns.violinplot(x="day", y="total_bill", data=tips, inner=None)
sns.swarmplot(x="day", y="total_bill", data=tips, color="w", alpha=.5);

img

类别内的统计估计

通常,不是显示每个类别中的分布,你可能希望显示值的集中趋势。 Seaborn有两种显示此信息的主要方法,但重要的是,这些功能的基本API与上述相同。(未禾:这是多么令人愉悦的事情)

条形图

最熟悉的方式完成这个目标是一个条形图。 在Seaborn中barplot()函数在完整数据集上运行,并显示任意估计,默认情况下使用均值。 当在每个类别中有多个观察值时,它还使用引导来计算估计周围的置信区间,并绘制使用误差条:

1
sns.barplot(x="sex", y="survived", hue="class", data=titanic);

img

条形图的特殊情况是当您想要显示每个类别中的观察次数,而不是计算第二个变量的统计量。这类似于分类而不是定量变量的直方图。在Seaborn中,使用countplot()函数很容易绘制:

未禾备注:函数将默认使用count参数作为x/y中未传的一组维度

1
sns.countplot(x="deck", data=titanic, palette="Greens_d");

img

可以使用上面讨论的所有选项来调用barplot()和countplot(),以及在每个函数的详细文档中的其他选项:

1
sns.countplot(y="deck", hue="class", data=titanic, palette="Greens_d");

img

点图

pointplot()函数提供了可视化相同信息的另一种风格。该函数还对另一轴的高度估计值进行编码,而不是显示一个完整的柱型,它只绘制点估计和置信区间。另外,点图连接相同hue类别的点。这使得很容易看出主要关系如何随着第二个变量的变化而变化,因为你的眼睛很好地收集斜率的差异:

1
sns.pointplot(x="sex", y="survived", hue="class", data=titanic);

img

为了使能够在黑白中重现的图形,可以使用不同的标记和线条样式来展示不同hue类别的层次:

1
2
3
sns.pointplot(x="class", y="survived", hue="sex", data=titanic,
palette={"male": "g", "female": "m"},
markers=["^", "o"], linestyles=["-", "--"]);

img

绘制“宽格式”数据

虽然使用“长格式”或“整洁”数据是优选的,但是这些功能也可以应用于各种格式的“宽格式”数据,包括pandas DataFrame或二维numpy数组阵列。这些对象应该直接传递给数据参数:

1
sns.boxplot(data=iris,orient="h");

img

此外,这些函数接受Pandas或numpy对象的向量,而不是DataFrame中的变量

1
sns.violinplot(x=iris.species, y=iris.sepal_length);

img

为了控制由上述功能制作的图形的大小和形状,您必须使用matplotlib命令自己设置图形。 当然,这也意味着这些图块可以和其他种类的图块一起在一个多面板的绘制中共存:

1
2
f, ax = plt.subplots(figsize=(7, 3))
sns.countplot(y="deck", data=titanic, color="c");

img

绘制多层面板分类图

正如我们上面提到的,有两种方法可以在Seaborn中绘制分类图。与回归图中的二元性相似,您可以使用上面介绍的函数,也可以使用更高级别的函数factorplot(),将这些函数与FacetGrid()相结合,通过这个图形的更大的结构来增加展示其他类别的能力。 默认情况下,factorplot()产生一个pairplot():

1
sns.factorplot(x="day", y="total_bill", hue="smoker", data=tips);

img

然而,kind参数可以让您选择以上讨论的任何种类的图:

1
sns.factorplot(x="day", y="total_bill", hue="smoker", data=tips, kind="bar");

img

使用factorplot()的主要优点是很容易调用”facet”展开更多其他分类变量:

1
2
sns.factorplot(x="day", y="total_bill", hue="smoker",
col="time", data=tips, kind="swarm");

img

任何一种图形都可以画出来。基于FacetGrid的工作原理,要更改图形的大小和形状,需要指定适用于每个方面的size和aspect参数:

1
2
sns.factorplot(x="time", y="total_bill", hue="smoker",
col="day", data=tips, kind="box", size=4, aspect=.5);

img

重要的是要注意,你也可以直接使用boxplot()和FacetGrid来制作这个图。但是,必须特别注意确保分类变量的顺序在每个方面实施,方法是使用具有Categorical数据类型的数据或通过命令和hue_order。

1
2
3
sns.factorplot(x="time", y="total_bill", hue="smoker",hue_order=["No","Yes"]
,col="day", data=tips, kind="box", size=4, aspect=.5,
palette="Set3");

img

由于分类图的广义API,它们应该很容易应用于其他更复杂的上下文。 例如,它们可以轻松地与PairGrid结合,以显示多个不同变量之间的分类关系:

1
2
3
4
5
g = sns.PairGrid(tips,
x_vars=["smoker", "time", "sex"],
y_vars=["total_bill", "tip"],
aspect=.75, size=3.5)
g.map(sns.violinplot, palette="pastel");

img

补充资料

最后在这章翻译结束后,未禾专门收集了这个重要函数的所有参数说明,方便参考:

seaborn.factorplot(x=None, y=None, hue=None, data=None, row=None, col=None, col_wrap=None, estimator=, ci=95, n_boot=1000, units=None, order=None, hue_order=None, row_order=None, col_order=None, kind=’point’, size=4, aspect=1, orient=None, color=None, palette=None, legend=True, legend_out=True, sharex=True, sharey=True, margin_titles=False, facet_kws=None, **kwargs)

Parameters:

  • x,y,hue 数据集变量 变量名
  • date 数据集 数据集名
  • row,col 更多分类变量进行平铺显示 变量名
  • col_wrap 每行的最高平铺数 整数
  • estimator 在每个分类中进行矢量到标量的映射 矢量
  • ci 置信区间 浮点数或None
  • n_boot 计算置信区间时使用的引导迭代次数 整数
  • units 采样单元的标识符,用于执行多级引导和重复测量设计 数据变量或向量数据
  • order, hue_order 对应排序列表 字符串列表
  • row_order, col_order 对应排序列表 字符串列表
  • kind : 可选:point 默认, bar 柱形图, count 频次, box 箱体, violin 提琴, strip 散点,swarm 分散点(具体图形参考文章前部的分类介绍)
  • size 每个面的高度(英寸) 标量
  • aspect 纵横比 标量
  • orient 方向 “v”/“h”
  • color 颜色 matplotlib颜色
  • palette 调色板 seaborn颜色色板或字典
  • legend hue的信息面板 True/False
  • legend_out 是否扩展图形,并将信息框绘制在中心右边 True/False
  • share{x,y} 共享轴线 True/False
  • facet_kws FacetGrid的其他参数 字典

感慨

终于抽时间把最重要的三章翻译完了,有了这三章seaborn在数据挖掘中已经可以覆盖到大部分数据格式,其快速做图能力已经可以得到足量的发挥。最近工作压力日趋增大,全文还有最难翻译的一章,会坚持在最近放出。最后吐槽下知乎的排版,代码+贴图非常不方便,费时费力唉。

如果文章对你有帮助,请不吝点个赞,方便更多的小伙伴能看到。

如果文章有理解、翻译谬误请留言,十分感谢!

【第五章完】

绘制数据网格

在探索中等维度数据时,一个有用的方法是在数据集的不同子集上绘制相同绘图的多个实例。这种技术有时被称为“格子”或“格子”绘图,它与“小倍数”的想法有关。 它允许观看者快速提取大量关于复杂数据的信息。 Matplotlib可以很好地支持制作具有多个轴的图形; seaborn建立在此之上,以将结构直接链接到数据集结构上进行绘制。

要使用这些功能,您的数据必须位于Pandas DataFrame中,并且必须采用Hadley Whickam称为“整洁”数据的形式。 简而言之,这意味着您的数据框架应该被结构化,使得每一列都是一个变量,每一行都是一个观测。

对于高级使用,您可以直接使用本教程本部分中讨论的对象,这将提供最大的灵活性。一些Seaborn功能(如lmplot(),factorplot()和pairplot())也在幕后使用。与其他Seaborn功能“Axes级别”不同,并且绘制在特定(可能已经存在的)matplotlib轴上,而无需其他操作的图形,这些较高级别的功能在调用时创建一个数字,并且通常更严格地说明如何设置。在某些情况下,对于这些函数或其依赖的类的构造函数的参数将提供与图形大小不同的接口属性,如lmplot()的情况,您可以在其中设置每个方面的高度和纵横比而不是整体尺寸。使用这些对象之一的任何函数总是在绘制之后返回,而且这些对象中的大多数都具有方便的方法来改变绘制,通常以更抽象和简单的方式。

1
2
3
4
5
6
7
8
9
10
%matplotlib inline
import numpy as np
import pandas as pd
import seaborn as sns
from scipy import stats
import matplotlib as mpl
import matplotlib.pyplot as plt

sns.set(style="ticks")
np.random.seed(sum(map(ord, "axis_grids")))

用FacetGrid子集数据

当您想要在数据集的子集内可视化变量的分布或多个变量之间的关系时,FacetGrid类很有用。 FacetGrid可以绘制最多三个维度:row,col和hue。前两者与所得轴数有明显的对应关系;将hue变量视为沿着深度轴的第三维,其中不同的级别用不同的颜色绘制。

通过使用数据框初始化FacetGrid对象和将形成网格的行,列或色调维度的变量的名称来使用该类。 这些变量应该是分类的或离散的,然后变量的每个级别的数据将用于沿该轴的小平面。 例如,假设我们要检查tips数据集中的午餐和晚餐之间的差异。

另外,lmplot()和factorplot()在内部使用这个对象,并且当它们被修改时,它们返回该对象,以便可以用于进一步的调整。

1
2
tips = sns.load_dataset("tips")
tips.head()

total_billtipsexsmokerdaytimesize016.991.01FemaleNoSunDinner 2110.341.66MaleNoSunDinner 3221.013.50MaleNoSunDinner 3323.683.31MaleNoSunDinner 2424.593.61FemaleNoSunDinner 4

1
g = sns.FacetGrid(tips, col="time")

img

像这样初始化网格设置了matplotlib图形和轴,但并没有绘制任何东西。

在此网格上可视化数据的主要方法是使用FacetGrid.map()方法,提供一个绘图功能和数据框中变量的名称来绘制。我们来看一下这些子集中提示的分布,使用直方图。

1
2
g = sns.FacetGrid(tips, col="time")
g.map(plt.hist, "tip");

img

此功能将绘制图形并注释轴,并在一个步骤中生成完成。 要做一个关系图,只需传递多个变量名。可以提供关键字参数,将其传递给绘图功能:

1
2
3
g = sns.FacetGrid(tips, col="sex", hue="smoker")
g.map(plt.scatter, "total_bill", "tip", alpha=.7)
g.add_legend();

img

有几个选项可以控制可以传递给类构造函数的网格的外观。

1
2
g = sns.FacetGrid(tips, row="smoker", col="time", margin_titles=True)
g.map(sns.regplot, "size", "total_bill", color=".3", fit_reg=False, x_jitter=.1);

img

请注意,matplotlib API没有正式支持margin_titles,并且在所有情况下都可能无法正常运行。 特别是,它目前不能用于图形之外的注释框。

通过提供每个图形的高度以及纵横比来达到设置图形大小的目的。

1
2
g = sns.FacetGrid(tips, col="day", size=4, aspect=.5)
g.map(sns.barplot, "sex", "total_bill");

img

在matplotlib大于1.4的版本中,可以传递在gridspec模块中的参数,增加其尺寸来吸引注意力。当然,在每个方面可视化不同数量的组的数据集的分布时,这无疑是特别实用的。

1
2
3
4
5
titanic = sns.load_dataset("titanic")
titanic = titanic.assign(deck=titanic.deck.astype(object)).sort_values("deck")
g = sns.FacetGrid(titanic, col="class", sharex=False,
gridspec_kws={"width_ratios": [5, 3, 3]})
g.map(sns.boxplot, "deck", "age");

img

这里,默认的顺序来自于DataFrame中的书序。如果用于定义facets具有分类变量的类型,则会实用类别的顺序。否则,facets将按照级别的顺序排列。当然,也可以使用适当的*_order参数来指定任何平面维度的数据顺序。

1
2
3
4
ordered_days = tips.day.value_counts().index
g = sns.FacetGrid(tips, row="day", row_order=ordered_days,
size=1.7, aspect=4,)
g.map(sns.distplot, "total_bill", hist=False, rug=True);

img

可以提供任何Seaborn调色板(即可以传递给color_palette()的参数),还可以使用将色调变量中值的名称映射到有效的matplotlib颜色的字典:

1
2
3
4
pal = dict(Lunch="seagreen", Dinner="gray")
g = sns.FacetGrid(tips, hue="time", palette=pal, size=5)
g.map(plt.scatter, "total_bill", "tip", s=50, alpha=.7, linewidth=.5, edgecolor="white")
g.add_legend();

img

您还可以让色调的其他方面在色相变量的水平上有所不同,这对于绘制黑白打印时将更易于理解的图形将有所帮助。 为此,将字典传递给hue_kws,其中键是绘图函数关键字参数的名称,值是关键字值的列表,每个级别的hue对应一个变量。

1
2
3
g = sns.FacetGrid(tips, hue="sex", palette="Set1", size=5, hue_kws={"marker": ["^", "v"]})
g.map(plt.scatter, "total_bill", "tip", s=100, linewidth=.5, edgecolor="white")
g.add_legend();

img

如果您有多个级别的一个变量,您可以沿着列绘制,但是”wrap”它们,以便跨越多个行。 当这样做时,将不能使用行(row)变量。

1
2
3
attend = sns.load_dataset("attention").query("subject <= 12")
g = sns.FacetGrid(attend, col="subject", col_wrap=4, size=2, ylim=(0, 10))
g.map(sns.pointplot, "solutions", "score", color=".3", ci=None);

img

使用FacetGrid.map()(可以多次调用)绘制图形之后,您可能需要调整绘图的某些方面。 FacetGrid对象上还有一些方法可以在更高层次的抽象上操作图形。 最通用的是FacetGrid.set(),还有其他更专门的方法,如FacetGrid.set_axis_labels(),它遵循内部方面没有轴标签的效果。 例如:

1
2
3
4
5
6
with sns.axes_style("white"):
g = sns.FacetGrid(tips, row="sex", col="smoker", margin_titles=True, size=2.5)
g.map(plt.scatter, "total_bill", "tip", color="#334488", edgecolor="white", lw=.5);
g.set_axis_labels("Total bill (US Dollars)", "Tip");
g.set(xticks=[10, 30, 50], yticks=[2, 6, 10]);
g.fig.subplots_adjust(wspace=.02, hspace=.02);

img

对于更多的定制,您可以直接使用underling matplotlib图形和Axes对象,它们分别作为图和轴(二维数组)的成员属性存储。 当没有行或列面的图形时,还可以使用ax属性直接访问单个轴。

1
2
3
4
5
g = sns.FacetGrid(tips, col="smoker", margin_titles=True, size=4)
g.map(plt.scatter, "total_bill", "tip", color="#338844", edgecolor="white", s=50, lw=1)
for ax in g.axes.flat:
ax.plot((0, 50), (0, .2 * 50), c=".2", ls="--")
g.set(xlim=(0, 60), ylim=(0, 14));

img

将自定义函数应用在网格上

在使用FacetGrid时,并不限于现有的matplotlib和Seaborn功能。但是,要正常工作,使用必须遵循以下规则:

  1. 必须绘制在“当前活动”的matplotlib轴上。 这对matplotlib.pyplot命名空间中的函数是正确的,如果要使用其方法,可以调用plt.gca来获取对当前Axes的直接引用。
  2. 它必须接受它在位置参数中绘制的数据。 在内部,FacetGrid将传递一系列针对传递给FacetGrid.map()的命名位置参数的数据。
  3. 它必须能够接受color和label关键字参数,理想情况下它将非常有用。在大多数情况下,使用一个通用的**kwargs字典是最简单的,并将其传递给底层的绘图函数。

我们来看一下您可以绘制的功能的最简单的例子。该函数只需要给出每个方向的向量的数据:

1
2
3
4
5
6
def quantile_plot(x, **kwargs):
qntls, xr = stats.probplot(x, fit=False)
plt.scatter(xr, qntls, **kwargs)

g = sns.FacetGrid(tips, col="sex", size=4)
g.map(quantile_plot, "total_bill");

img

如果我们想做一个双变量图,你应该编写函数,以便它接受x轴为第一个变量和y轴为第二个变量:

1
2
3
4
5
6
7
def qqplot(x, y, **kwargs):
_, xr = stats.probplot(x, fit=False)
_, yr = stats.probplot(y, fit=False)
plt.scatter(xr, yr, **kwargs)

g = sns.FacetGrid(tips, col="smoker", size=4)
g.map(qqplot, "total_bill", "tip");

img

因为plt.scatter接受color和label关键字参数并正确运行,我们可以简单的再添加一个hue参数:

1
2
3
g = sns.FacetGrid(tips, hue="time", col="sex", size=4)
g.map(qqplot, "total_bill", "tip")
g.add_legend();

img

这种方法还允许我们使用额外的sns设置来区分hue变量的级别,依赖这些关键字的参数将使得显示摆脱对刻面变量的依赖:

1
2
3
4
g = sns.FacetGrid(tips, hue="time", col="sex", size=4,
hue_kws={"marker": ["s", "D"]})
g.map(qqplot, "total_bill", "tip", s=40, edgecolor="w")
g.add_legend();

img

一些时候,将需要映射一个适合的color和label关键字参数以达到预期的效果。在这种情况下,您将会有明确地把握并熟悉处理自定义函数的逻辑。例如这种方法将允许使用映射plt.hexbin函数和那些类似的不方便使用FacetGrid API的调用:

1
2
3
4
5
6
7
def hexbin(x, y, color, **kwargs):
cmap = sns.light_palette(color, as_cmap=True)
plt.hexbin(x, y, gridsize=15, cmap=cmap, **kwargs)

with sns.axes_style("dark"):
g = sns.FacetGrid(tips, hue="time", col="time", size=4)
g.map(hexbin, "total_bill", "tip", extent=[0, 50, 0, 10]);

img

用PairGrid and pairplot()绘制成对的关系

PairGrid还允许您使用相同的绘图类型快速绘制小子图的网格,以在每个图形中显示数据。在一个PairGrid中,每个行和列分配给一个不同的变量,所以生成的图显示了数据集中的每个成对关系。这种风格的绘图有时被称为“散点图矩阵”,因为这是显示每个关系的最常见方式,但是PairGrid不仅限于散点图。

了解FacetGrid和PairGrid之间的区别很重要。在前者中,每个方面显示出与其他变量的不同级别相同的关系。在后者中,每个图都显示不同的关系(尽管上下三角形将具有镜像图)。使用PairGrid可以为您提供非常快速,非常高级的汇总数据集中有趣的关系。

该类的基本用法与FacetGrid非常相似。首先初始化网格,然后将绘图函数传递给map方法,并在每个子图上调用它。还有一个配套功能,pairplot()交易了一些灵活性更快的绘图。

1
2
3
iris = sns.load_dataset("iris")
g = sns.PairGrid(iris)
g.map(plt.scatter);

img

可以在对角线上绘制不同的函数,以显示每列中变量的单变量分布。 请注意,轴刻度线将不对应于该图的计数或密度轴。

1
2
3
g = sns.PairGrid(iris)
g.map_diag(plt.hist)
g.map_offdiag(plt.scatter);

img

使用该图的非常常见的方法是通过单独的分类变量来绘制观察值。 例如,虹膜数据集对于三种不同种类的鸢尾花中的每一种进行四次测量,以便您可以看到它们如何不同。

1
2
3
4
g = sns.PairGrid(iris, hue="species")
g.map_diag(plt.hist)
g.map_offdiag(plt.scatter)
g.add_legend();

img

默认情况下,使用数据集中的每个数字列,但如果需要,您可以专注于特定的关系。

1
2
g = sns.PairGrid(iris, vars=["sepal_length", "sepal_width"], hue="species")
g.map(plt.scatter);

img

也可以在上下三角形中使用不同的功能来强调关系的不同方面。

1
2
3
4
g = sns.PairGrid(iris)
g.map_upper(plt.scatter)
g.map_lower(sns.kdeplot, cmap="Blues_d")
g.map_diag(sns.kdeplot, lw=3, legend=False);

img

具有对角线上的身份关系的方形网格实际上只是一个特殊情况,您可以在行和列中绘制不同的变量。

1
2
3
g = sns.PairGrid(tips, y_vars=["tip"], x_vars=["total_bill", "size"], size=4)
g.map(sns.regplot, color=".3")
g.set(ylim=(-1, 11), yticks=[0, 5, 10]);

img

当然,sns属性是可配置的。 例如,您可以使用不同的调色板(例如,显示色调变量的顺序),并将关键字参数传递到绘图函数中。

1
2
3
g = sns.PairGrid(tips, hue="size", palette="GnBu_d")
g.map(plt.scatter, s=50, edgecolor="white")
g.add_legend();

img

PairGrid是灵活的,但是要快速查看一个数据集,可以使用pairplot()更容易。 默认情况下,该功能使用散点图和直方图,但是还可以添加其他几种(目前还可以绘制对角线上的对角线和KDEs的回归图)。

1
sns.pairplot(iris, hue="species", size=2.5);

img

您还可以使用关键字参数控制显示细节,并返回PairGrid实例进行进一步的调整。

1
g = sns.pairplot(iris, hue="species", palette="Set2", diag_kind="kde", size=2.5)

img

松了口气,最终全部完成了,没有烂尾。有时间未禾将对每个章节进行再次的校对和注释,感谢诸多朋友的支持和鼓励,闲暇也许还会针对这六章内容出一个快速上手笔记,感谢!

【全文完】

-------------感谢阅读-------------
0%