估计回归拟合#
许多数据集包含多个定量变量,分析的目标通常是将这些变量彼此关联。我们之前讨论过可以做到这一点的函数,方法是显示两个变量的联合分布。但是,使用统计模型来估计两个有噪声的观测集之间的简单关系非常有帮助。本章讨论的函数将通过线性回归的通用框架来做到这一点。
本着 Tukey 的精神,seaborn 中的回归图主要用于添加视觉指南,帮助在探索性数据分析过程中突出显示数据集中的模式。也就是说,seaborn 本身不是一个用于统计分析的软件包。要获得与回归模型拟合相关的定量度量,您应该使用statsmodels。但是,seaborn 的目标是使通过可视化来探索数据集变得快速简便,因为这样做与(甚至比)通过统计表来探索数据集同样重要(甚至更重要)。
用于绘制线性回归模型的函数#
可以用来可视化线性拟合的两个函数是regplot()
和lmplot()
。
在最简单的调用中,这两个函数都会绘制两个变量x
和y
的散点图,然后拟合回归模型y ~ x
并绘制生成的回归线以及该回归的 95% 置信区间
tips = sns.load_dataset("tips")
sns.regplot(x="total_bill", y="tip", data=tips);
sns.lmplot(x="total_bill", y="tip", data=tips);
这些函数绘制了类似的图形,但regplot()
是一个轴级函数,而lmplot()
是一个图级函数。此外,regplot()
接受各种格式的x
和y
变量,包括简单的 numpy 数组、pandas.Series
对象,或者作为传递给data
的pandas.DataFrame
对象中变量的引用。相比之下,lmplot()
将data
作为必需参数,并且必须将x
和y
变量指定为字符串。最后,只有lmplot()
有hue
作为参数。
但是,核心功能是相似的,因此本教程将重点介绍lmplot()
。
当其中一个变量取离散值时,可以拟合线性回归,但是,这种数据集产生的简单散点图通常不是最佳的
sns.lmplot(x="size", y="tip", data=tips);
一种选择是在离散值中添加一些随机噪声(“抖动”),以使这些值的分布更加清晰。请注意,抖动仅应用于散点图数据,不会影响回归线拟合本身
sns.lmplot(x="size", y="tip", data=tips, x_jitter=.05);
另一种选择是将每个离散箱中的观测值折叠起来,以绘制中心趋势的估计值以及置信区间
sns.lmplot(x="size", y="tip", data=tips, x_estimator=np.mean);
拟合不同类型的模型#
上面使用的简单线性回归模型非常容易拟合,但是,它不适用于某些类型的数据集。安斯库姆四重奏 数据集展示了一些例子,其中简单线性回归提供了相同的关系估计,而简单目视检查清楚地显示了差异。例如,在第一个案例中,线性回归是一个很好的模型
anscombe = sns.load_dataset("anscombe")
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'I'"),
ci=None, scatter_kws={"s": 80});
第二个数据集中的线性关系相同,但图形清楚地表明这并不是一个好模型
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'II'"),
ci=None, scatter_kws={"s": 80});
在存在这种更高阶关系的情况下,lmplot()
和regplot()
可以拟合多项式回归模型,以探索数据集中简单的非线性趋势
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'II'"),
order=2, ci=None, scatter_kws={"s": 80});
由“异常值”观测值造成的不同问题,这些观测值偏离了研究中的主要关系
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'III'"),
ci=None, scatter_kws={"s": 80});
在存在异常值的情况下,拟合稳健回归可能会有用,稳健回归使用不同的损失函数来降低相对较大的残差的权重
sns.lmplot(x="x", y="y", data=anscombe.query("dataset == 'III'"),
robust=True, ci=None, scatter_kws={"s": 80});
当y
变量是二元时,简单的线性回归也会“起作用”,但会提供不可信的预测
tips["big_tip"] = (tips.tip / tips.total_bill) > .15
sns.lmplot(x="total_bill", y="big_tip", data=tips,
y_jitter=.03);
这种情况下的解决方案是拟合逻辑回归,使得回归线显示给定x
值时y = 1
的估计概率
sns.lmplot(x="total_bill", y="big_tip", data=tips,
logistic=True, y_jitter=.03);
请注意,逻辑回归估计在计算上要复杂得多(稳健回归也是如此)。由于回归线周围的置信区间是使用引导程序过程计算的,您可能希望将其关闭以更快地迭代(使用ci=None
)。
一种完全不同的方法是使用lowess 平滑器 拟合非参数回归。这种方法的假设最少,尽管它在计算上很密集,因此目前根本没有计算置信区间
sns.lmplot(x="total_bill", y="tip", data=tips,
lowess=True, line_kws={"color": "C1"});
residplot()
函数可以作为检查简单回归模型是否适合数据集的工具。它拟合并删除简单线性回归,然后绘制每个观测值的残差值。理想情况下,这些值应该随机散布在y = 0
附近
sns.residplot(x="x", y="y", data=anscombe.query("dataset == 'I'"),
scatter_kws={"s": 80});
如果残差中存在结构,则表明简单的线性回归不合适
sns.residplot(x="x", y="y", data=anscombe.query("dataset == 'II'"),
scatter_kws={"s": 80});
根据其他变量进行条件化#
上面的图形展示了许多探索一对变量之间关系的方法。然而,更有趣的问题通常是“这两个变量之间的关系如何随着第三个变量的变化而变化?” 这就是regplot()
和lmplot()
之间的主要区别所在。虽然regplot()
始终显示单个关系,但lmplot()
将regplot()
与FacetGrid
结合起来,使用hue
映射或分面显示多个拟合。
分离关系的最佳方法是在同一轴上绘制两个级别,并使用颜色来区分它们
sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips);
与relplot()
不同,无法将不同的变量映射到散点图的样式属性,但可以使用标记形状冗余地编码hue
变量
sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips,
markers=["o", "x"], palette="Set1");
要添加另一个变量,可以绘制多个“分面”,每个变量级别都出现在网格的行或列中
sns.lmplot(x="total_bill", y="tip", hue="smoker", col="time", data=tips);
sns.lmplot(x="total_bill", y="tip", hue="smoker",
col="time", row="sex", data=tips, height=3);
在其他环境中绘制回归#
其他一些 seaborn 函数在更大型、更复杂的图形中使用regplot()
。第一个是我们在分布教程 中介绍的jointplot()
函数。除了之前讨论的图形样式外,jointplot()
可以通过传递kind="reg"
来使用regplot()
在联合轴上显示线性回归拟合
sns.jointplot(x="total_bill", y="tip", data=tips, kind="reg");
使用 pairplot()
函数并设置 kind="reg"
可以结合 regplot()
和 PairGrid
来展示数据集变量之间的线性关系。请注意这与 lmplot()
的区别。在下面的图表中,两个轴并没有展示在第三个变量的两个水平条件下的相同关系;相反,PairGrid()
用于展示数据集变量之间不同配对的多重关系。
sns.pairplot(tips, x_vars=["total_bill", "size"], y_vars=["tip"],
height=5, aspect=.8, kind="reg");
使用 hue
参数可以在这两个函数中构建额外的分类变量条件。
sns.pairplot(tips, x_vars=["total_bill", "size"], y_vars=["tip"],
hue="smoker", height=5, aspect=.8, kind="reg");