统计分析是了解数据集中的变量如何相互关联以及这些关系如何依赖于其他变量的过程。可视化是此过程的核心组件,这是因为当数据被恰当地可视化时,人的视觉系统可以看到指示关系的趋势和模式。
这里介绍三个seaborn
函数。我们最常用的是relplot()
。这是一个figure-level
的函数,可以用散点图和线图两种通用的方法来可视化统计关系。relplot()
将FacetGrid
与两个axes-level
函数组合在一起:
scatterplot()
(kind="scatter"
;默认值)lineplot()
(kind="line"
)
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings("ignore")
sns.set_theme(style="darkgrid")
pd.show_versions()
INSTALLED VERSIONS
------------------
commit : a671b5a8bf5dd13fb19f0e88edc679bc9e15c673
python : 3.11.5.final.0
python-bits : 64
OS : Darwin
OS-release : 22.6.0
Version : Darwin Kernel Version 22.6.0: Tue Nov 7 21:48:06 PST 2023; root:xnu-8796.141.3.702.9~2/RELEASE_X86_64
machine : x86_64
processor : i386
byteorder : little
LC_ALL : None
LANG : zh_CN.UTF-8
LOCALE : zh_CN.UTF-8
pandas : 2.1.4
numpy : 1.24.3
pytz : 2023.3.post1
dateutil : 2.8.2
setuptools : 68.2.2
pip : 23.3.1
Cython : None
pytest : 7.4.0
hypothesis : None
sphinx : 5.0.2
blosc : None
feather : None
xlsxwriter : None
lxml.etree : 4.9.3
html5lib : None
pymysql : None
psycopg2 : None
jinja2 : 3.1.2
IPython : 8.15.0
pandas_datareader : None
bs4 : 4.12.2
bottleneck : 1.3.5
dataframe-api-compat: None
fastparquet : None
fsspec : 2023.10.0
gcsfs : None
matplotlib : 3.8.0
numba : 0.58.1
numexpr : 2.8.7
odfpy : None
openpyxl : 3.0.10
pandas_gbq : None
pyarrow : 11.0.0
pyreadstat : None
pyxlsb : None
s3fs : 2023.10.0
scipy : 1.11.4
sqlalchemy : 2.0.21
tables : 3.8.0
tabulate : 0.9.0
xarray : 2023.6.0
xlrd : None
zstandard : 0.19.0
tzdata : 2023.3
qtpy : 2.4.1
pyqt5 : None
用散点图关联变量
散点图是数据可视化的支柱,它通过点云描绘了两个变量的联合分布,其中每个点代表数据集中的一个观测值。这种描述能够使我们通过视觉推断出许多信息,他们之间是否存在任何有意义的关系。
在seaborn
中有多种方式绘制散点图。当两个变量的是数值型时,最基本的是函数scatterplot()
。scatterplot()
是relplot()
中kind
的默认类型(也可以通过kind="scatter"
来设置):
tips = sns.load_dataset('tips')
tips.head()
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
sns.relplot(x='total_bill', y='tip', data=tips)
<seaborn.axisgrid.FacetGrid at 0x137708ed0>
虽然这些点是以二维绘制的,但可以通过根据第三个变量对点进行着色来将另一个维度添加到绘图中。在 seaborn 中,这被称为使用“色调语义”,因为该点的颜色获得了意义:
sns.relplot(x='total_bill', y='tip', hue='smoker', data=tips)
<seaborn.axisgrid.FacetGrid at 0x13789be90>
为了强调类别之间的差异并提高可访问性,可以为每个类别使用不同的标记样式:
sns.relplot(x='total_bill', y='tip', hue='smoker', style='smoker', data=tips)
<seaborn.axisgrid.FacetGrid at 0x141860d10>
也可以通过单独改变每个点的色调和样式来表示四个变量。但是这应该谨慎,因为眼睛对形状的敏感度远低于对颜色的敏感度:
sns.relplot(x='total_bill', y='tip', hue='smoker', style='time', data=tips)
<seaborn.axisgrid.FacetGrid at 0x141908910>
在上面的例子中,色调语义表示类别,所以使用了默认的定性调色板。如果色调语义表示数值(特别是,如果它可以转换为浮点数),默认的颜色切换到顺序调色板:
sns.relplot(x='total_bill', y='tip', hue='size', data=tips)
<seaborn.axisgrid.FacetGrid at 0x1419f31d0>
在这两种情况下,您都可以自定义调色板,有多种方式可以实现。在这里,我们使用cubehelix_palette()
的字符串接口自定义一个顺序调色板:
sns.relplot(x='total_bill', y='tip', hue='size', palette='ch:r=-0.5, l=0.75',data=tips)
<seaborn.axisgrid.FacetGrid at 0x1419db650>
第三个语义变量改变每个点的大小:
sns.relplot(x='total_bill', y='tip', size='size', data=tips)
<seaborn.axisgrid.FacetGrid at 0x141a38850>
与matplotlib.pyplot.scatter()
不同,变量的值不用于直接决定点的面积。数据单位中的值范围被规范化为面积单位的范围,这个范围可以自定义:
sns.relplot(x='total_bill', y='tip', size='size', sizes=(15, 200), data=tips)
<seaborn.axisgrid.FacetGrid at 0x141bc04d0>
强调线图的连续性
散点图是非常有效的,但是没有通用的最优可视化类型。相反,可视表示应该适应数据集的细节以及你试图用图表回答的问题。
对于某些数据集,你可能希望了解一个变量中的变化关于时间的函数,或者类似的连续变量。在这种情况下,一个很好的选择是绘制线图。在seaborn
中,这可以通过lineplot()
函数直接实现,也可以通过设置relplot()
参数kind='line'
来实现。
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()
聚合表示不确定性
更复杂的数据集将对x
变量的相同值有多个观测值。seaborn
的默认行为是通过绘制平均值及95%
的置信区间,在每个x
周围聚合多个测量值:
fmri = sns.load_dataset('fmri')
fmri.head()
subject | timepoint | event | region | signal | |
---|---|---|---|---|---|
0 | s13 | 18 | stim | parietal | -0.017552 |
1 | s5 | 14 | stim | parietal | -0.080883 |
2 | s12 | 18 | stim | parietal | -0.081033 |
3 | s11 | 18 | stim | parietal | -0.046134 |
4 | s10 | 18 | stim | parietal | -0.037970 |
sns.relplot(x='timepoint', y='signal', kind='line', data=fmri)
<seaborn.axisgrid.FacetGrid at 0x130a266d0>
置信区间是使用bootstrapping
计算的,对于较大的数据集,它可能是时间密集型的。因此,可以禁用它们:
sns.relplot(x='timepoint', y='signal', kind='line', ci=None, data=fmri)
<seaborn.axisgrid.FacetGrid at 0x130a7d490>
尤其是对于较大的数据,另一个不错的选择是通过绘制标准差,而不是置信区间来表示分布在每个时间点的分布范围:
sns.relplot(x='timepoint', y='signal', kind='line', ci='sd', data=fmri)
<seaborn.axisgrid.FacetGrid at 0x1307ae6d0>
可以通过设置estimator
参数为None
,来完全停用聚合。当数据在每个点上有多个观察值时,这可能会产生奇怪的效果。
sns.relplot(x='timepoint', y='signal', kind='line', estimator=None, data=fmri)
<seaborn.axisgrid.FacetGrid at 0x130b6e590>
用语义映射绘制数据子集
函数lineplot()
与scatterplot()
具有相同的灵活性:它可以通过修改绘图元素的色调,大小和样式来显示最多三个附加变量。它使用于scatterplot()
相同的API
,这意味着我们不需要停下来考虑控制matplotlib
中线条与点外观的参数。
lineplot()
中使用语义也将决定数据的聚合方式。例如,添加具有两个级别的色调语义将绘图分成两行以及错误带,每个都着色以指示它们对应于哪个数据集。
sns.relplot(x='timepoint', y='signal', hue='event', kind='line', data=fmri)
<seaborn.axisgrid.FacetGrid at 0x130c1f0d0>
在线条图中添加样式语义默认情况下会改变线条中的破折号模式:
sns.relplot(x='timepoint', y='signal', style='event', hue='region', kind='line', data=fmri)
<seaborn.axisgrid.FacetGrid at 0x130e90510>
与散点图一样,要谨慎使用多个语义制作线图。虽然有时提供信息,但它们也很难解析和解释。但当您只检查一个附加变量的变化时,更改线条的颜色和样式也很有用。当打印成黑白或有色盲的人观看时,这可以使绘图更容易访问:
sns.relplot(x='timepoint', y='signal', style='event', hue='event', kind='line', data=fmri)
<seaborn.axisgrid.FacetGrid at 0x130f5b010>
当使用重复测量数据(即有多次采样的单位)时,还可以单独绘制每个采样单位,而无需通过语义区分它们。这样可以避免使图例混乱:
sns.relplot(x="timepoint", y="signal", hue="region",
units="subject", estimator=None,
kind="line", data=fmri.query("event == 'stim'"))
<seaborn.axisgrid.FacetGrid at 0x130fcb950>
用日期数据绘图
线图通常用于可视化与实际日期和时间相关的数据。这些函数以原始格式将数据传递给底层的matplotlib
函数,因此他们可以利用matplotlib
在tick
标签中设置日期格式的功能。但是所有这些格式化都必须在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()
显示与切面的多种关系
当你想要了解两个变量之间的关系如何依赖于多个其他变量时呢?
最好的方法可能是多次绘制。因为relplot()
基于FacetGrid
,所以这很容易做到。要显示附加变量的影响,而不是将其分配给图中的一个语义角色,而是使用它来“切面”可视化。这意味着我们可以创建多个轴并在每个轴上绘制数据的子集:
sns.relplot(x="total_bill", y="tip", hue="smoker",
col="time", data=tips)
<seaborn.axisgrid.FacetGrid at 0x13100f5d0>
还可以通过这种方式显示两个变量的影响:一个是通过在列上切面而另一个是在行上切面。当开始向网格添加更多变量时,可能希望减小图形大小。请记住,大小FacetGrid
由每个切面的高度和长宽比参数化的:
sns.relplot(x="timepoint", y="signal", hue="subject",
col="region", row="event", height=3,
kind="line", estimator=None, data=fmri)
<seaborn.axisgrid.FacetGrid at 0x131185350>
当想要检查一个变量的多个级别的效果时,在列上对该变量进行切面处理,然后将切面“包装”到行中:
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'"))
<seaborn.axisgrid.FacetGrid at 0x1314ae590>