58

如果我在 Python 中使用 seaborn 库来绘制线性回归的结果,有没有办法找出回归的数值结果?例如,我可能想知道拟合系数或拟合的 R 2

我可以使用底层 statsmodels 接口重新运行相同的拟合,但这似乎是不必要的重复工作,无论如何我希望能够比较结果系数以确保数值结果与我的结果相同我在情节中看到了。

4

3 回答 3

33

没有办法做到这一点。

在我看来,要求可视化库为您提供统计建模结果是倒退的。statsmodels,一个建模库,可让您拟合模型,然后绘制与您拟合的模型完全对应的图。如果您想要精确的对应关系,那么这种操作顺序对我来说更有意义。

您可能会说“但其中的情节statsmodels没有像seaborn”那样多的美学选择。但我认为这是有道理的——statsmodels是一个建模库,有时在建模服务中使用可视化。seaborn是一个可视化库,有时在可视化服务中使用建模。专注于专业是好的,而尝试做任何事情都是不好的。

幸运的是,两者都seaborn使用statsmodels整洁的数据。这意味着您真的需要很少的重复工作即可通过适当的工具获得绘图和模型。

于 2014-04-04T02:09:14.993 回答
14

不幸的是, 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它可能随时中断。

于 2020-01-15T17:47:32.383 回答
2

通过当前可用的文档,我能够确定现在是否可以满足此功能的最接近的方法是使用 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 线图轻松获得的东西。

于 2014-06-24T20:50:17.460 回答