Seaborn中文教程(一):可视化变量间的关系

众所周知,Seaborn“可能”是Python下最友好、易用的可视化工具了,可视化效果也非常好。但是截止目前,并没有一份中文教程供广大国内Python使用者查阅学习。怎么能因为语言的问题,让大家错过这么好用的一个可视化工具呢?

思考再三,我决定花一些时间将官方的英文文档整理出来,为大家提供一份最权威的中文教程。考虑到我的时间比较碎片化,这项工作可能会在未来的几周内完成,感兴趣的朋友可以先关注和收藏下,后续的更新会在CSDN和我的个人博客中数洞或者备用站发布。

今天,我整理了第一部分:如何用Seaborn可视化变量之间的关系,这一部分非常实用,基本上学习后马上就能给我们带来很多帮助。那么接下来,就开始我们的学习吧!

文章较长,建议收藏后在PC站或者我的个人博客阅读。


统计分析是这样的一个过程:尝试去理解一个数据集中变量之间的关系,以及这些关系如何受到其他变量的影响。可视化是这个过程的核心元素,因为当数据以非常恰当的方式展示出来时,我们可以非常直观地观察到某些趋势或者模式,而这些,就揭示了变量之间的关系。

在这篇教程中,我们会讨论三个seaborn函数。我们用的最多的是relplot()。这是一个图形级别的函数,它用散点图和线图两种常用的手段来表现统计关系。relplot()使用两个坐标轴级别的函数来结合了FacetGrid

  • scatterplot():(使用kind="scatter",这是默认参数)
  • lineplot():(使用`kind=“line”)

正如我们所见,这些函数非常直白,因为它们用了简单易懂的展示方式,却可以呈现复杂的数据集结构。这是因为通过huesizestyle参数,我们可以在二维图形中表现出更多的变量(除了x轴和y轴的两个,还可以通过不同的方式额外展示3个变量)。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="darkgrid")

一、用散点图展示相关变量

散点图是统计图形中的中流砥柱。它用一系列的散点将两个变量的联合分布描绘出来,其中每个点就是一个观测样本。这种描述方式可以让我们从视觉上推断出大量信息,来判断两个变量之间是否存在某种有意义的关系。

seaborn中,我们有数种方法可以实现散点图的绘制。最基本的一种适用于两个变量都是数值型变量的情况,它就是scatterplot()。在分类可视化教程中,我们会看到如何绘制分类数据的散点图。relplot()的默认类型(kind)就是scatterplot()(当然,我们也可以强制指定参数kind="scatter",这和不指定这一参数时效果是一样的)。

tips = sns.load_dataset("tips")
sns.relplot(x="total_bill", y="tip", data=tips);

png

当我们已经将散点绘制在二维的平面上时,我们还可以根据第三个变量来对这些点施以不同的颜色,从而引入一个新的维度。在seaborn中,我们用hue参数实现了这种想法,因为点的颜色是有意义的。

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

png

如果我们想要强调不同分类之间的差异,同时增加易读性,我们可以对不同的分类使用不同的标记样式:

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

png

我们也可以同时展示四个变量,只需要将huestyle参数单独调整到不同的分类变量即可。但是我们要谨慎使用这种方法,因为我们的眼睛对于形状的敏感性远远不如对颜色的敏感性。

sns.relplot(x="total_bill", y="tip", hue="smoker", style="time", data=tips);

png

在上边这个例子中,hue参数对应的变量是分类型数据,因此seaborn自动为它应用了默认的定性(分类)调色板。如果hue参数对应的变量是数值型的(可转化为浮点数的),那么默认的颜色也会随之变为连续的定量调色板。

sns.relplot(x="total_bill", y="tip", hue="size", data=tips);

png

上述两种情况下(分类或连续数据),我们都可以自定义我们的调色板。有很多选项可以实现这一目的。下面,我们使用cubehelix_palette()的字符串接口来定制我们的连续调色板:

sns.relplot(x="total_bill", y="tip", hue="size", 
            palette="ch:r=-.5,l=.75", data=tips);

png

我们还可以使用点的大小来引入第三个额外的变量:

sns.relplot(x="total_bill", y="tip", size="size", data=tips);

png

matplotlib.pyplot.scatter()不同的是,这里并不是使用原始数据中的数值来为每个点选择面积大小,seaborn将原始数据归一化(正则化)到了某个范围,这个范围可以由我们来指定:

sns.relplot(x="total_bill", y="tip", size="size", sizes=(15, 200), data=tips);

png

更多关于如何定制不同参数来展示统计关系的示例可以在scatterplot()的API中找到。

二、使用线图表现连续性

散点图很高效,但是没有哪种可视化类型可以完美应对所有情况。事实上,我们的可视化呈现方式要适应数据集的种类以及我们想要通过图形回答的问题。

在某些数据集中,我们可能想要理解某个变量随着时间的变化规律,或者想要理解某个连续型的变量。这种情况下,线图会是一个不错的选择。在seaborn中,我们可以通过lineplot()函数或者使用带有kind="line"参数的relplot()来实现线图的绘制。

df = pd.DataFrame(dict(time=np.arange(500), value=np.random.randn(500).cumsum()))
g = sns.relplot(x="time", y="value", kind="line", data=df)
g.fig.autofmt_xdate()

png

由于lineplot()假设用户在大多数情况下是在尝试描绘y相对于x的函数(变化规律),因此它在绘制之前会默认先对x做一个排序。不过我们可以禁止它。

df = pd.DataFrame(np.random.randn(500, 2).cumsum(axis=0), columns=["x", "y"])
sns.relplot(x="x", y="y", sort=False, kind="line", data=df);

png

聚合并展示不确定性

在更多复杂的数据集中,会出现一个x轴变量对应了多个观测值(y)的情况。seaborn会默认将多个观测值聚合起来,并且将它们的均值以及95%的置信区间展示出来:

fmri = sns.load_dataset("fmri")
sns.relplot(x="timepoint", y="signal", kind="line", data=fmri);

png

置信区间是通过自助采样法(bootstrapping)计算的,这在遇到大型数据集时可以帮助我们节省时间。当然,我们也可以禁止它。

sns.relplot(x="timepoint", y="signal", ci=None, kind="line", data=fmri);

png

另一个不错的选择是,我们可以用标准差替代置信区间来展示每个时间点下观测值的分布,当数据集比较大时这一选择尤其明智。

sns.relplot(x="timepoint", y="signal", kind="line", ci="sd", data=fmri);

png

如果想要关闭所有的聚合操作,我们可以设置estimator=None。不过当同一时间点存在多个观测值时,我们的图会看起来有些奇怪。

sns.relplot(x="timepoint", y="signal", estimator=None, kind="line", data=fmri);

png

通过参数映射可视化数据子集

lineplot()scatterplot()一样具有很强的灵活性:它也可以通过huesizestyle参数来展示额外的三个变量。它和scatterplot()使用了相同的API,因此我们不需要停下来绞尽脑汁地思考哪些参数是用来控制线条、哪些参数是用来控制散点。

使用不同的参数会决定我们的数据如何聚合。比如,增加一个具有两个水平的分类变量作为hue参数,会将我们的图形分为两条线以及两个误差带,并分别施以不同的颜色来区分数据的分类归属。

sns.relplot(x="timepoint", y="signal", hue="event", 
            kind="line", data=fmri);

png

我们可以增加一个style参数,以不同的线条样式来展示不同的分类:

sns.relplot(x="timepoint", y="signal",  hue="region",  
            style="event", kind="line", data=fmri);

png

我们还可以设置不同分类的标记样式,标记样式既可以和线条样式同时设置,也可以各自单独设置。

sns.relplot(x="timepoint", y="signal", hue="region", style="event", 
            dashes=False, markers=True, kind="line", data=fmri);

png

跟散点图一样,我们要慎重使用这些参数来展示太多变量。有些时候它们会展示丰富的信息,但是有些时候它们会使图形太过复杂导致我们难以解析和解释它。然而当你仅打算考虑额外的一个变量时,同时修改它们的颜色和样式会很有帮助。当需要考虑到色盲人群时,将图形颜色设置为黑白色调则是一个不错的选择。

sns.relplot(x="timepoint", y="signal", hue="event", style="event",
            kind="line", data=fmri);

png

当我们需要应对重复测量的数据时,我们可以将不同的抽样单元(单次实验观测到的数据系列)分离开来展示,这并不需要我们使用一个语义参数(hue/style/size)。后者会导致图例看起来像一个灾难(想象一下几十个分类的情况):

sns.relplot(x="timepoint", y="signal",  hue="region", 
            units="subject", estimator=None, kind="line", 
            data=fmri.query("event == 'stim'"));

png

scatterplot()类似,lineplot()默认的调色板以及图例处理方式也取决于hue对应的数据是分类型还是连续数值型。

dots = sns.load_dataset("dots").query("align == 'dots'")
sns.relplot(x="time", y="firing_rate",
            hue="coherence", style="choice",
            kind="line", data=dots);

png

hue参数对应的变量的数据是均匀分布在对数刻度上的(即数据分布范围非常大,比如从1到1亿),即使是连续的调色板也无法很好地应对这种情况。但是我们可以使用列表或者字典对每条线指定一个颜色。

palette = sns.cubehelix_palette(light=.8, n_colors=6)
sns.relplot(x="time", y="firing_rate",
            hue="coherence", style="choice",
            palette=palette,
            kind="line", data=dots);

png

或者我们可以直接修改调色板数值的正则方式:

from matplotlib.colors import LogNorm
palette = sns.cubehelix_palette(light=.7, n_colors=6)
sns.relplot(x="time", y="firing_rate", hue="coherence", style="choice",
            hue_norm=LogNorm(), kind="line", data=dots);

png

不要忘了我们还有个size参数,它用来修改线条的宽度:

sns.relplot(x="time", y="firing_rate", size="coherence", 
            style="choice", kind="line", data=dots);

png

size一般接受连续数值型变量,但是我们也可以传入分类型变量。但是要慎重考虑这种做法,因为这样比“粗线 vs. 细线”的区分难多了。然而,当数据具有非常高频的变异性时,我们使用style表现的不同线条样式会很难区分,这时使用不同的线条宽度就是一个更高效的选择了:

sns.relplot(x="time", y="firing_rate",
           hue="coherence", size="choice",
           palette=palette,
           kind="line", data=dots);

png

绘制时间序列数据

线图常用来描绘日期、时间相关的诗句。这些方法以原始格式传入更底层的matplotlib函数中,这样它们就可以利用matplotlib的能力来格式化日期数据。但是所有的时间格式化过程都是在matplotlib层实现的,想要知道更多实现的细节就需要去看一下matplotlib中关于这部分的文档:

df = pd.DataFrame(dict(time=pd.date_range("2017-1-1", periods=500),
                       value=np.random.randn(500).cumsum()))
g = sns.relplot(x="time", y="value", kind="line", data=df)
g.fig.autofmt_xdate()

png

三、用更多子图展示多重关系

前边我们已经强调过,虽然我们可以在一张图中展示数个不同的语义变量(通过hue/style/size参数),但是这么做并不是总会高效。那么当我们真的很想理解在某些额外变量的影响下两个变量之间的关系有什么不同时怎么办呢?

最好的办法就是画更多的图。由于relplot()是基于FacetGrid的,因此这很容易做到。当我们想要表现出一个额外变量的影响时,我们可以不用将它赋给前边提到的语义参数(hue/style/size),而是用它来将图形“面板”化。这意味着我们会创建多个坐标轴,分别用来绘制不同的子数据集:

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

png

我们还可以同时使用col(列)和row(行)参数来展示两个变量的影响。当我们在图中增加了更多的变量时(会有更多的子图),我们可能会想要调整图形的大小。要记住在FacetGrid中,我们用height(子图高度)和aspect(高宽比)来定制每个子图的大小:

sns.relplot(x="timepoint", y="signal", hue="subject", col="region", 
            row="event", height=3, kind="line", estimator=None, data=fmri);

png

当我们想要检验某个具有大量水平的变量的影响时,我们可以将这个变量赋给col参数,同时我们通过col_wrap参数设置每行达到多少列就换行:

sns.relplot(x="timepoint", y="signal", hue="event", style="event",
            col="subject", col_wrap=5,
            height=3, aspect=.75, linewidth=2.5,
            kind="line", data=fmri.query("region == 'frontal'"));

png

这种常被叫做“格子图”或“small-multiples”的可视化方式,非常高效,因为它们呈现数据的方式使得我们很容易同时发现整体的模式以及不同模式之间的偏差。当你需要利用scatterplot()relplot()的灵活性来表现更多信息时,一定要记住,多幅简单的图通常比一幅复杂的图更加高效。

1. 目录 1. 目录 2 2. 绘图函数Plotting functions 4 2.1. 可视化的统计关系Visualizing statistical relationships 4 2.1.1. 用散点图联系变量Relating variables with scatter plots 4 2.1.2. 强调线条图的连续性Emphasizing continuity with line plots 10 2.1.3. 显示与切面的多个关系Showing multiple relationships with facets 21 2.2. 分类数据绘图Plotting with categorical data 24 2.2.1. 分类散点图Categorical scatterplots 26 2.2.2. 分类观测值分布Distributions of observations within categories 31 2.2.3. 分类统计估计Statistical estimation within categories 37 2.2.4. 对“wide-form”数据作图Plotting “wide-form” data 41 2.2.5. 显示与facet的多个关系Showing multiple relationships with facets 43 2.3. 可视化数据集的分布Visualizing the distribution of a dataset 44 2.3.1. 绘制单变量分布Plotting univariate distributions 45 2.3.2. 绘制二元分布Plotting bivariate distributions 51 2.3.3. 在数据集中可视化成对关系Visualizing pairwise relationships in a dataset 55 2.4. 可视化线性关系Visualizing linear relationships 57 2.4.1. 函数绘制线性模型Functions to draw linear regression models 58 2.4.2. 拟合不同种类的模型Fitting different kinds of models 61 2.4.3. 在其他变量上的情况Conditioning on other variables 68 2.4.4. 控制图表的大小和形状Controlling the size and shape of the plot 71 2.4.5. 在其他上下文中绘制回归图Plotting a regression in other contexts 73 3. 多图网格Multi-plot grids 76 3.1. 构建结构化的多图网格Building structured multi-plot grids 76 3.2. 有条件的小倍数Conditional small multiples 77 3.3. 使用定制函数Using custom functions 86 3.4. 绘制成对的数据关系Plotting pairwise data relationships 90 4. 绘图美学Plot aesthetics 99 4.1. 控制图表美学Controlling figure aesthetics 99 4.1.1. Seaborn图表风格Seaborn figure styles 101 4.1.2. 删除轴上的小凸起Removing axes spines 104 4.1.3. 临时设置图表样式Temporarily setting figure style 105 4.1.4. 覆盖Seaborn样式的元素Overriding elements of the seaborn styles 106 4.1.5. 缩放图表元素Scaling plot elements 108 4.2. 选择调色板Choosing color palettes 111 4.2.1. 创建颜色调色板Building color palettes 111 4.2.2. 定性调色板Qualitative color palettes 112 4.2.3. 连续调色板Sequential color palettes 116 4.2.4. 不同颜色的调色板Diverging color palettes 122 4.2.5. 设置默认调色板Setting the default color palette 124 5. 教程中的数据集 125
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

量化祛魅师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值