【问题标题】:Coefficients for Logistic Regression scikit-learn vs statsmodelsLogistic 回归 scikit-learn 与 statsmodels 的系数
【发布时间】:2020-09-12 07:09:14
【问题描述】:

当使用这两个 API 执行逻辑回归时,它们会给出不同的系数。 即使使用这个简单的示例,它也不会在系数方面产生相同的结果。我遵循旧建议中关于同一主题的建议,例如在 sklearn 中为参数 C 设置一个较大的值,因为它使惩罚几乎消失(或设置惩罚 =“none”)。

import pandas as pd
import numpy as np
import sklearn as sk
from sklearn.linear_model import LogisticRegression
import statsmodels.api as sm

n = 200

x = np.random.randint(0, 2, size=n)
y = (x > (0.5 + np.random.normal(0, 0.5, n))).astype(int)

display(pd.crosstab( y, x ))


max_iter = 100

#### Statsmodels
res_sm = sm.Logit(y, x).fit(method="ncg", maxiter=max_iter)
print(res_sm.params)

#### Scikit-Learn
res_sk = LogisticRegression( solver='newton-cg', multi_class='multinomial', max_iter=max_iter, fit_intercept=True, C=1e8 )
res_sk.fit( x.reshape(n, 1), y )
print(res_sk.coef_)

例如,我只是运行上面的代码并得到 1.72276655 的 statsmodels 和 1.86324749 的 sklearn。当多次运行时,它总是给出不同的系数(有时比其他的更接近,但无论如何)。

因此,即使使用那个玩具示例,这两个 API 也给出了不同的系数(所以优势比),而对于真实数据(此处未显示),它几乎会“失控”...

我错过了什么吗?我怎样才能产生相似的系数,例如在逗号后至少有一两个数字?

【问题讨论】:

标签: python machine-learning scikit-learn logistic-regression statsmodels


【解决方案1】:

您的代码存在一些问题。

首先,您在此处显示的两个模型等效:尽管您将 scikit-learn LogisticRegressionfit_intercept=True(这是默认设置)相匹配,但您不用你的 statsmodels 这样做;来自 statsmodels docs:

默认情况下不包含拦截,应由用户添加。见statsmodels.tools.add_constant

这似乎是一个常见的混淆点 - 参见例如scikit-learn & statsmodels - which R-squared is correct?(以及自己的答案)。

另一个问题是,尽管您处于二进制分类设置中,但您在 LogisticRegression 中要求 multi_class='multinomial',但情况并非如此。

第三个问题是,如相关交叉验证线程Logistic Regression: Scikit Learn vs Statsmodels 中所述:

scikit-learn 中没有办法关闭正则化,但是可以通过将调优参数 C 设置为较大的数字使其失效。

这使得这两个模型在原则上再次不可比,但您已经通过设置C=1e8 成功解决了这个问题。事实上,从那时起(2016 年),scikit-learn 确实添加了一种关闭正则化的方法,通过设置 penalty='none' since,根据 docs

如果“无”(liblinear 求解器不支持),则不应用正则化。

现在应该将其视为关闭正则化的规范方法。

因此,将这些更改合并到您的代码中,我们有:

np.random.seed(42) # for reproducibility

#### Statsmodels
# first artificially add intercept to x, as advised in the docs:
x_ = sm.add_constant(x)
res_sm = sm.Logit(y, x_).fit(method="ncg", maxiter=max_iter) # x_ here
print(res_sm.params)

结果如下:

Optimization terminated successfully.
         Current function value: 0.403297
         Iterations: 5
         Function evaluations: 6
         Gradient evaluations: 10
         Hessian evaluations: 5
[-1.65822763  3.65065752]

数组的第一个元素是截距,第二个元素是x 的系数。而对于 scikit 学习,我们有:

#### Scikit-Learn

res_sk = LogisticRegression(solver='newton-cg', max_iter=max_iter, fit_intercept=True, penalty='none')
res_sk.fit( x.reshape(n, 1), y )
print(res_sk.intercept_, res_sk.coef_)

结果是:

[-1.65822806] [[3.65065707]]

在机器的数值精度范围内,这些结果实际上是相同的。

np.random.seed() 的不同值重复该过程不会改变上述结果的本质。

【讨论】:

  • 谢谢!我将 fit_intercept 设置为 True 或 False 但当然仍然会得到不同的系数,因为“主要”问题与 multi_class 参数有关。我认为将其设置为“多项式”不会改变二进制分类的行为......啊,我的错!再次感谢!
猜你喜欢
  • 2018-10-29
  • 2017-12-31
  • 2017-08-30
  • 2018-12-26
  • 2015-10-12
  • 2014-03-30
  • 2018-04-09
  • 2022-08-17
相关资源
最近更新 更多