我们用的最多的是relplot()
。这是一个图形级别的函数,它用散点图和线图两种常用的手段来表现统计关系。
relplot()使用两个坐标轴级别的函数来结合了FacetGrid:
scatterplot()
:(使用kind="scatter"
,这是默认参数)lineplot()
:(使用``kind=“line`”)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)
参数hue
当我们已经将散点绘制在二维的平面上时,我们还可以根据第三个变量来对这些点施以不同的颜色,从而引入一个新的维度。在seaborn中,我们用hue参数实现了这种想法,因为点的颜色是有意义的。
参数hue
如果我们想要强调不同分类之间的差异,同时增加易读性,我们可以对不同的分类使用不同的标记样式:
sns.relplot(x="total_bill", y="tip", hue="smoker", style="smoker", data=tips)
参数:style
我们也可以同时展示四个变量,只需要将hue
和style
参数单独调整到不同的分类变量即可。但是我们要谨慎使用这种方法,因为我们的眼睛对于形状的敏感性远远不如对颜色的敏感性。
sns.relplot(x="total_bill", y="tip", hue="smoker", style="time", data=tips)
在上边这个例子中,hue
参数对应的变量是分类型数据,因此seaborn自动为它应用了默认的定性(分类)调色板。如果hue参数对应的变量是数值型的(可转化为浮点数的),那么默认的颜色也会随之变为连续的定量调色板。
上述两种情况下(分类或连续数据),我们都可以自定义我们的调色板。有很多选项可以实现这一目的。下面,我们使用cubehelix_palette()
的字符串接口来定制我们的连续调色板:
sns.relplot(x="total_bill", y="tip", hue="size",
palette="ch:r=-.5,l=.75", data=tips)
参数size
我们还可以使用点的大小来引入第三个额外的变量:
sns.relplot(x="total_bill", y="tip", size="size", data=tips);
参数sizes
与matplotlib.pyplot.scatter()不同的是,这里并不是使用原始数据中的数值来为每个点选择面积大小,seaborn将原始数据归一化(正则化)到了某个范围,这个范围可以由我们来指定:
sns.relplot(x="total_bill", y="tip", size="size", sizes=(15, 200), data=tips)
在某些数据集中,我们可能想要理解某个变量随着时间的变化规律,或者想要理解某个连续型的变量。这种情况下,线图会是一个不错的选择。在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()
参数:sort
由于lineplot()
假设用户在大多数情况下是在尝试描绘y相对于x的函数(变化规律),因此它在绘制之前会默认先对x做一个排序。不过我们可以禁止它。
聚合并展示不确定性
参数:ci
在更多复杂的数据集中,会出现一个x轴变量对应了多个观测值(y)的情况。seaborn会默认将多个观测值聚合起来,并且将它们的均值以及95%的置信区间展示出来:
fmri = sns.load_dataset("fmri")
sns.relplot(x="timepoint", y="signal", kind="line", data=fmri)
置信区间是通过自助采样法(bootstrapping)
计算的,这在遇到大型数据集时可以帮助我们节省时间。当然,我们也可以禁止它。
另一个不错的选择是,我们可以用标准差替代置信区间来展示每个时间点下观测值的分布,当数据集比较大时这一选择尤其明智。
sns.relplot(x="timepoint", y="signal", kind="line", ci="sd", data=fmri)
参数:ciestimator
如果想要关闭所有的聚合操作,我们可以设置estimator=None。不过当同一时间点存在多个观测值时,我们的图会看起来有些奇怪。
sns.relplot(x="timepoint", y="signal",
estimator=None,
kind="line",
data=fmri
)
lineplot()
与scatterplot()
一样具有很强的灵活性:它也可以通过hue
、size
和style
参数来展示额外的三个变量。它和scatterplot()使用了相同的API,因此我们不需要停下来绞尽脑汁地思考哪些参数是用来控制线条、哪些参数是用来控制散点。
使用不同的参数会决定我们的数据如何聚合。比如,增加一个具有两个水平的分类变量作为hue参数
,会将我们的图形分为两条线以及两个误差带,并分别施以不同的颜色来区分数据的分类归属。
sns.relplot(x="timepoint", y="signal", hue="event",
kind="line", data=fmri)
我们可以增加一个·style参数
,以不同的线条样式来展示不同的分类:
sns.relplot(x="timepoint", y="signal", hue="region",
style="event", kind="line", data=fmri)
我们还可以设置不同分类的标记样式,标记样式既可以和线条样式同时设置,也可以各自单独设置。
sns.relplot(x="timepoint", y="signal", hue="region",
style="event",
dashes=False, ##
markers=True,
kind="line",
data=fmri)
跟散点图一样,我们要慎重使用这些参数来展示太多变量。有些时候它们会展示丰富的信息,但是有些时候它们会使图形太过复杂导致我们难以解析和解释它。然而当你仅打算考虑额外的一个变量时,同时修改它们的颜色和样式会很有帮助。
sns.relplot(x="timepoint", y="signal",
hue="event",
style="event",
kind="line", data=fmri);
当我们需要应对重复测量的数据时,我们可以将不同的抽样单元(单次实验观测到的数据系列)分离开来展示,这并不需要我们使用一个语义参数(hue
/style
/size
)。后者会导致图例看起来像一个灾难(想象一下几十个分类的情况):
sns.relplot(x="timepoint", y="signal", hue="region",
units="subject", estimator=None, kind="line",
data=fmri.query("event == 'stim'"));
与scatterplot()
类似,lineplot()
默认的调色板以及图例处理方式也取决于hue
对应的数据是分类型还是连续数值型。
ots = sns.load_dataset("dots").query("align == 'dots'")
sns.relplot(x="time", y="firing_rate",
hue="coherence", style="choice",
kind="line", data=dots);
当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);
参数size
sns.relplot(x="time", y="firing_rate", size="coherence",
style="choice", kind="line", data=dots);
线图常用来描绘日期、时间相关的诗句。这些方法以原始格式传入更底层的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()
前边我们已经强调过,虽然我们可以在一张图中展示数个不同的语义变量(通过hue/style/size
参数),但是这么做并不是总会高效。那么当我们真的很想理解在某些额外变量的影响下两个变量之间的关系有什么不同时怎么办呢?
最好的办法就是画更多的图。由于relplot()是基于FacetGrid
的,因此这很容易做到。当我们想要表现出一个额外变量的影响时,我们可以不用将它赋给前边提到的语义参数(hue/style/size
),而是用它来将图形“面板”化。这意味着我们会创建多个坐标轴,分别用来绘制不同的子数据集:
参数:col
sns.relplot(x="total_bill", y="tip",
hue="smoker",
col="time",
data=tips);
我们还可以同时使用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)
参数:col_wrap
当我们想要检验某个具有大量水平的变量的影响时,我们可以将这个变量赋给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'"));
这种常被叫做“格子图”或“small-multiples”的可视化方式,非常高效,因为它们呈现数据的方式使得我们很容易同时发现整体的模式以及不同模式之间的偏差。当你需要利用scatterplot()和relplot()的灵活性来表现更多信息时,一定要记住,多幅简单的图通常比一幅复杂的图更加高效。