如果我在 Python 中使用 seaborn 库来绘制线性回归的结果,有没有办法找出回归的数值结果?例如,我可能想知道拟合系数或拟合的 R 2。
我可以使用底层 statsmodels 接口重新运行相同的拟合,但这似乎是不必要的重复工作,无论如何我希望能够比较结果系数以确保数值结果与我的结果相同我在情节中看到了。
没有办法做到这一点。
在我看来,要求可视化库为您提供统计建模结果是倒退的。statsmodels
,一个建模库,可让您拟合模型,然后绘制与您拟合的模型完全对应的图。如果您想要精确的对应关系,那么这种操作顺序对我来说更有意义。
您可能会说“但其中的情节statsmodels
没有像seaborn
”那样多的美学选择。但我认为这是有道理的——statsmodels
是一个建模库,有时在建模服务中使用可视化。seaborn
是一个可视化库,有时在可视化服务中使用建模。专注于专业是好的,而尝试做任何事情都是不好的。
幸运的是,两者都seaborn
使用statsmodels
整洁的数据。这意味着您真的需要很少的重复工作即可通过适当的工具获得绘图和模型。
不幸的是, Seaborn 的创建者表示他不会添加这样的功能。下面是一些选项。(最后一部分包含我最初的建议,这是一个使用私有实现细节的 hack,seaborn
并且不是特别灵活。)
regplot
以下函数在散点图上覆盖一条拟合线并从statsmodels
. 这支持 最简单,也许是最常见的用法sns.regplot
,但没有实现任何更高级的功能。
import statsmodels.api as sm
def simple_regplot(
x, y, n_std=2, n_pts=100, ax=None, scatter_kws=None, line_kws=None, ci_kws=None
):
""" Draw a regression line with error interval. """
ax = plt.gca() if ax is None else ax
# calculate best-fit line and interval
x_fit = sm.add_constant(x)
fit_results = sm.OLS(y, x_fit).fit()
eval_x = sm.add_constant(np.linspace(np.min(x), np.max(x), n_pts))
pred = fit_results.get_prediction(eval_x)
# draw the fit line and error interval
ci_kws = {} if ci_kws is None else ci_kws
ax.fill_between(
eval_x[:, 1],
pred.predicted_mean - n_std * pred.se_mean,
pred.predicted_mean + n_std * pred.se_mean,
alpha=0.5,
**ci_kws,
)
line_kws = {} if line_kws is None else line_kws
h = ax.plot(eval_x[:, 1], pred.predicted_mean, **line_kws)
# draw the scatterplot
scatter_kws = {} if scatter_kws is None else scatter_kws
ax.scatter(x, y, c=h[0].get_color(), **scatter_kws)
return fit_results
结果statsmodels
包含大量信息,例如:
>>> print(fit_results.summary())
OLS Regression Results
==============================================================================
Dep. Variable: y R-squared: 0.477
Model: OLS Adj. R-squared: 0.471
Method: Least Squares F-statistic: 89.23
Date: Fri, 08 Jan 2021 Prob (F-statistic): 1.93e-15
Time: 17:56:00 Log-Likelihood: -137.94
No. Observations: 100 AIC: 279.9
Df Residuals: 98 BIC: 285.1
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const -0.1417 0.193 -0.735 0.464 -0.524 0.241
x1 3.1456 0.333 9.446 0.000 2.485 3.806
==============================================================================
Omnibus: 2.200 Durbin-Watson: 1.777
Prob(Omnibus): 0.333 Jarque-Bera (JB): 1.518
Skew: -0.002 Prob(JB): 0.468
Kurtosis: 2.396 Cond. No. 4.35
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
sns.regplot
与我在下面的原始答案相比,上述方法的优势在于很容易将其扩展到更复杂的拟合。
无耻的插件:这是我编写的一个扩展regplot
函数,它实现了大部分sns.regplot
功能:https ://github.com/ttesileanu/pydove 。
虽然仍然缺少一些功能,但我写的功能
statsmodels
计算置信区间而不是使用自举。log(x)
)。不幸的是, Seaborn 的创建者表示他不会添加这样的功能,所以这里有一个解决方法。
def regplot(
*args,
line_kws=None,
marker=None,
scatter_kws=None,
**kwargs
):
# this is the class that `sns.regplot` uses
plotter = sns.regression._RegressionPlotter(*args, **kwargs)
# this is essentially the code from `sns.regplot`
ax = kwargs.get("ax", None)
if ax is None:
ax = plt.gca()
scatter_kws = {} if scatter_kws is None else copy.copy(scatter_kws)
scatter_kws["marker"] = marker
line_kws = {} if line_kws is None else copy.copy(line_kws)
plotter.plot(ax, scatter_kws, line_kws)
# unfortunately the regression results aren't stored, so we rerun
grid, yhat, err_bands = plotter.fit_regression(plt.gca())
# also unfortunately, this doesn't return the parameters, so we infer them
slope = (yhat[-1] - yhat[0]) / (grid[-1] - grid[0])
intercept = yhat[0] - slope * grid[0]
return slope, intercept
请注意,这仅适用于线性回归,因为它只是从回归结果中推断出斜率和截距。好消息是它使用了seaborn
自己的回归类,因此可以保证结果与显示的一致。缺点当然是我们使用了一个私有的实现细节,seaborn
它可能随时中断。
通过当前可用的文档,我能够确定现在是否可以满足此功能的最接近的方法是使用 scipy.stats.pearsonr 模块。
r2 = stats.pearsonr("pct", "rdiff", df)
在试图使其直接在 Pandas 数据框中工作时,由于违反了基本的 scipy 输入要求而引发了一个错误:
TypeError: pearsonr() takes exactly 2 arguments (3 given)
我设法找到了另一个显然解决了它的 Pandas Seaborn 用户:https ://github.com/scipy/scipy/blob/v0.14.0/scipy/stats/stats.py#L2392
sns.regplot("rdiff", "pct", df, corr_func=stats.pearsonr);
但是,不幸的是,我没有设法让它工作,因为似乎作者创建了他自己的自定义“corr_func”,或者有一个未记录的 Seaborn 争论传递方法,可以使用更手动的方法:
# x and y should have same length.
x = np.asarray(x)
y = np.asarray(y)
n = len(x)
mx = x.mean()
my = y.mean()
xm, ym = x-mx, y-my
r_num = np.add.reduce(xm * ym)
r_den = np.sqrt(ss(xm) * ss(ym))
r = r_num / r_den
# Presumably, if abs(r) > 1, then it is only some small artifact of floating
# point arithmetic.
r = max(min(r, 1.0), -1.0)
df = n-2
if abs(r) == 1.0:
prob = 0.0
else:
t_squared = r*r * (df / ((1.0 - r) * (1.0 + r)))
prob = betai(0.5*df, 0.5, df / (df + t_squared))
return r, prob
希望这有助于将这个原始请求推进到一个临时解决方案,因为非常需要实用程序将回归适应度统计数据添加到 Seaborn 包中,以替代人们可以从 MS-Excel 或库存的 Matplotlib 线图轻松获得的东西。