为啥使用 Seaborn 绘制回归时截距显示不正确?

Posted

技术标签:

【中文标题】为啥使用 Seaborn 绘制回归时截距显示不正确?【英文标题】:Why is an intercept displayed incorrectly when plotting regression with Seaborn?为什么使用 Seaborn 绘制回归时截距显示不正确? 【发布时间】:2018-09-26 17:14:24 【问题描述】:

我已经建立了一个线性回归模型来检查来自这个dataset 的两个变量(chemical_1chemical_2)之间的关系。 根据结果​​,intercept = 16.83488364225717

我刚刚开始发现数据科学的数学基础知识,我目前对截距的理解是,它是回归线与 y-axis(和 x=0)相交的值。所以现在我对使用 Seaborn 构建的结果感到困惑。

为什么它显示在 10 和 12 之间穿过 y-axis 的回归线,而不是截距 (16.83488364225717) 和 x=0 的实际值?我应该怎么做才能解决这个问题?

这是我的代码:

from scipy import stats

X = df['chemical_1']
Y = df['chemical_2']

slope, intercept, r_value, p_value, slope_std_error = stats.linregress(X,Y)
print ("slope = " + str(slope))
print ("intercept = " + str(intercept))
print ("r_squared = " + str(r_value**2))
print ("r_value = " + str(r_value))
print ("p_value = " +str(p_value))

slope = -0.9345759557752411
intercept = 16.83488364225717
r_squared = 0.04205938806347038
r_value = -0.20508385617466426
p_value = 0.00784469031490164

predict_y = slope * X + intercept

fig, ax = plt.subplots()
sns.set(color_codes=True)
sns.set(rc='figure.figsize':(10, 10))
ax = sns.regplot(x=X, y=Y, line_kws='label':'$y=%3.7s*x+%3.7s$'%(slope, intercept));
sns.regplot(x=X, y=Y, fit_reg=False, ax=ax);
sns.regplot(x=X, y=predict_y,scatter=False, ax=ax);
ax.set_ylabel('chemical_2')
ax.legend()
plt.show()

UPD:当我使用 Simon 提出的解决方案时 - 扩展轴的限制,截距仍然没有显示,情节看起来像这样: 当我使用 set_ylim(0,20) 时,绘图上的数据看起来很紧凑。实际上,我设置的任何轴参数(默认值除外)都会导致数据和图上的置信区间看起来被压缩。

【问题讨论】:

如果查看 x 轴,您会看到 x 轴从 6 下方开始,而不是 0。截距是函数在 x=0 处与 y 轴相交的位置,不是 x=6.8 @YngveMoe 是否可以将其可视化,以便 x-axis 从 0 开始,截距在 16.83488364225717 处与 y-axis 交叉? 【参考方案1】:

如 cmets 中所述,当 X 的值为 0 时,截距是 Y 的值。因此,您的 X 轴范围不允许显示实际截距

import numpy as np
from scipy import stats
import seaborn as sns

np.random.seed(1236)
X = np.arange(5,10) + np.random.normal(0,1,5)
Y = np.arange(5,10) + np.random.normal(0,1,5)

slope, intercept, r_value, p_value, slope_std_error = stats.linregress(X,Y)
predict_y = slope * X + intercept

print("slope = " + str(slope))
print("intercept = " + str(intercept))

sns.regplot(x=X, y=Y, fit_reg=False)
sns.regplot(x=X, y=predict_y,scatter=False)

这里我们可以看到截距是0.115:

slope = 0.9897768121234015
intercept = 0.11521162448067557

这给出了一个看起来像这样的 seaborn 图:

如果你想真正看到交叉点,你想做的就是扩展你的轴的范围:

p = sns.regplot(x=X, y=Y, fit_reg=False)
p.axes.set_xlim(0,)
p.axes.set_ylim(0,)
sns.regplot(x=X, y=predict_y,scatter=False)

编辑:

如果您想在扩大轴限制时解决数据压缩问题,您可以通过计算 Z 分数来标准化您的数据:

X = np.arange(5,10) + np.random.normal(0,1,5)
Y = np.arange(5,10) + np.random.normal(0,1,5)
X = stats.zscore(X)
Y = stats.zscore(Y)

slope, intercept, r_value, p_value, slope_std_error = stats.linregress(X,Y)
predict_y = slope * X + intercept

print("slope = " + str(slope))
print("intercept = " + str(intercept))

sns.regplot(x=X, y=Y, fit_reg=False)
sns.regplot(x=X, y=predict_y,scatter=False)

参数值:

slope = 0.667021422528575
intercept = -2.8128800822178726e-16

非常需要注意的是,在这种情况下,您的 XY 不再包含在其原始指标中。所以现在对斜率的解释是“X 增加 1 个标准差,Y 的值将增加 0.667 个标准差”。但是您会看到截距现在基本上为 0(即 X=0 时 Y 的值),并且显示在图的中心

【讨论】:

解决方案未按预期工作。你能看看我的问题中的更新吗? set_ylim(0,) 采用 2 个参数。第一个是下限,第二个是上限。在我的示例中,我将下限设置为 0。在您的情况下,您似乎需要扩展 Y 轴的上限,以便截距在范围内。类似set_ylim(0,20),甚至set_ylim(,20)。您可以使用这些值,直到情节以您想要的方式显示 配置轴有问题,当我尝试这样做时,图上的数据和置信区间被挤压。用图片更新了我的问题。 在这种情况下你能做的最好的事情就是set_ylim(,20)set_xlim(0,)。如果您想同时查看数据和截距,那么它看起来仍然有些挤压,因为您没有任何覆盖缺失范围的数据 解决此问题的一种方法是将您的 XY 值标准化,这样您就不需要玩限制,但这会极大地改变您对结果的解释

以上是关于为啥使用 Seaborn 绘制回归时截距显示不正确?的主要内容,如果未能解决你的问题,请参考以下文章

ggplot2:绘制具有不同截距但具有相同斜率的回归线

为啥 sklearn 逻辑回归正则化权重和截距?

为啥要绘制一个似乎不正确的直方图?

seaborn 的 lmplot 的输出没有绘制散点图和线性回归

Seaborn - 绘制不同类型的回归(Regression)曲线

如何在 seaborn 中显示正确的计数值?