如何使用`lmplot`绘制无截距的线性回归?

24
lmplot 是 seaborn 中用于拟合带有截距的回归模型的函数。但是,有时我想要拟合不带截距的回归模型,即通过原点的回归。
例如:
In [1]: import numpy as np
   ...: import pandas as pd
   ...: import seaborn as sns
   ...: import matplotlib.pyplot as plt
   ...: import statsmodels.formula.api as sfa
   ...: 

In [2]: %matplotlib inline
In [3]: np.random.seed(2016)
In [4]: x = np.linspace(0, 10, 32)
In [5]: y = 0.3 * x + np.random.randn(len(x))
In [6]: df = pd.DataFrame({'x': x, 'y': y})
In [7]: r = sfa.ols('y ~ x + 0', data=df).fit()
In [8]: sns.lmplot(x='x', y='y', data=df, fit_reg=True)
Out[8]: <seaborn.axisgrid.FacetGrid at 0xac88a20>

enter image description here

In [9]: fig, ax = plt.subplots(figsize=(5, 5))
   ...: ax.scatter(x=x, y=y)
   ...: ax.plot(x, r.fittedvalues)
   ...: 
Out[9]: [<matplotlib.lines.Line2D at 0x5675a20>]

输入图像描述


4
抱歉,这不是一个选择。 - mwaskom
@mwaskom 未来有计划支持它吗? - Eastsun
1
@mwaskom 你可能想把那个作为答案发布,并附上一些文档链接。 - Zaccharie Ramzi
2
@mnagel 这个问题不是已经被回答了吗,例如这个问题:https://dev59.com/MGkw5IYBdhLWcg3wUIxW? - ImportanceOfBeingErnest
3个回答

1
Seaborn API不直接允许更改线性回归模型。
调用链是:
- 在某个时刻,调用`_RegressionPlotter.plot()`来生成图表 - 它调用`_RegressionPlotter.lineplot()`来执行拟合绘图 - 它本身调用位于`regression`模块中的fit_regression方法 - 然后调用许多Seaborn回归方法,例如在您的情况下的`self.fit_fast(grid)`。
要使用不同的回归模型,您可以:
- Monkey patch`_RegressionPlotter`类并更改`lineplot()`行为 - Monkey patch`regression`模块中的`fit_regression()`或`fit_fast()`方法
为了进行这样的 seaborn 猴子补丁,您可以参考我之前回答过的 一个做相同类型黑客的答案。这是不好的,圣诞老人可能不会高兴。 这意味着您可以动态修改 seaborn 以适应您的目的。
当然,您需要实现自己的回归模型,使其符合 y = a * x 的规律,而不是 y = (a * x) + bimportanceofbeingernest 已经在评论中指出了 this SO question
一个优雅的方法是构建自己的图表,但你已经在自己的问题中回答了这个部分。
引用你自己的问题(我没有检查提供的代码):
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.formula.api as sfa

np.random.seed(2016)
x = np.linspace(0, 10, 32)
y = 0.3 * x + np.random.randn(len(x))
df = pd.DataFrame({'x': x, 'y': y})
r = sfa.ols('y ~ x + 0', data=df).fit()
fig, ax = plt.subplots(figsize=(5, 5))
ax.scatter(x=x, y=y)
ax.plot(x, r.fittedvalues)

-1
如果只是为了显示目的,您可以通过将y轴刻度调整为数据的平均值来进行调整。
您可以尝试以下操作:
sns.lmplot(x='x', y='y', data=df, fit_reg=True)
y_ticks = [int(round(ytick - np.mean(y), 0)) for ytick in plt.gca().get_yticks()]
plt.gca().set_yticklabels(y_ticks)

请注意,这不会改变行本身或任何内部内容,只是已准备好的可视化效果。

我认为这不等同于拟合一个无截距模型。斜率也会因是否拟合截距而有所不同。 - xcmkz
@xcmkz 是的,它通常不会改变模型,只是在光学上移动轴。如果模型应该反映它,我想唯一有效的选择是 (i) 拟合一个没有截距的公共线性回归(例如使用 sklearn),然后 (ii) 用学习到的斜率将线条作为单独的演员绘制到轴上。 - Ric Hard

-5

这符合你的目的吗?

sns.lmplot(x='x', y='y', data=df, fit_reg=False)

我们仍然需要线性回归线,但它必须通过(0,0)。 - James Schinner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接