逻辑回归:Scikit Learn 与 Statsmodels

机器算法验证 回归 物流 Python scikit-学习 统计模型
2022-01-31 06:43:06

我试图理解为什么这两个库的逻辑回归输出会给出不同的结果。

我正在使用来自 UCLA idre tutorial的数据集,admit基于和进行预测被视为分类变量,因此首先将其转换为删除的虚拟变量。还添加了截距列。gregparankrankrank_1

py
from patsy import dmatrices
from sklearn.linear_model import LogisticRegression
import pandas as pd
import statsmodels.api as sm

df = pd.read_csv("https://stats.idre.ucla.edu/stat/data/binary.csv")
y, X = dmatrices('admit ~ gre + gpa + C(rank)', df, return_type = 'dataframe')
X.head()
>  Intercept  C(rank)[T.2]  C(rank)[T.3]  C(rank)[T.4]  gre   gpa
0          1             0             1             0  380  3.61
1          1             0             1             0  660  3.67
2          1             0             0             0  800  4.00
3          1             0             0             1  640  3.19
4          1             0             0             1  520  2.93

# Output from scikit-learn
model = LogisticRegression(fit_intercept = False)
mdl = model.fit(X, y)
model.coef_
> array([[-1.35417783, -0.71628751, -1.26038726, -1.49762706,  0.00169198,
     0.13992661]]) 
# corresponding to predictors [Intercept, rank_2, rank_3, rank_4, gre, gpa]

# Output from statsmodels
logit = sm.Logit(y, X)
logit.fit().params
> Optimization terminated successfully.
     Current function value: 0.573147
     Iterations 6
Intercept      -3.989979
C(rank)[T.2]   -0.675443
C(rank)[T.3]   -1.340204
C(rank)[T.4]   -1.551464
gre             0.002264
gpa             0.804038
dtype: float64

的输出statsmodels与 idre 网站上显示的相同,但我不确定为什么 scikit-learn 会产生一组不同的系数。它是否最小化了一些不同的损失函数?是否有任何说明实施的文件?

3个回答

您弄清楚这一点的线索应该是,来自 scikit-learn 估计的参数估计在幅度上一致小于 statsmodels 对应项。这可能会让您相信 scikit-learn 应用了某种参数正则化。您可以通过阅读scikit-learn 文档来确认这一点

在 scikit-learn 中无法关闭正则化,但可以通过将调优参数设置C为较大的数字来使其无效。在您的情况下,这是如何工作的:

# module imports
from patsy import dmatrices
import pandas as pd
from sklearn.linear_model import LogisticRegression
import statsmodels.discrete.discrete_model as sm

# read in the data & create matrices
df = pd.read_csv("http://www.ats.ucla.edu/stat/data/binary.csv")
y, X = dmatrices('admit ~ gre + gpa + C(rank)', df, return_type = 'dataframe')

# sklearn output
model = LogisticRegression(fit_intercept = False, C = 1e9)
mdl = model.fit(X, y)
model.coef_

# sm
logit = sm.Logit(y, X)
logit.fit().params

更新:正如下面评论中正确指出的那样,现在您可以通过设置关闭 scikit-learn 中的正则化penalty='none'(请参阅文档)。

是什么绊倒了我:

  • 禁用 sklearn 正则化LogisticRegression(C=1e9)

  • 添加 statsmodels 拦截sm.Logit(y,sm.add_constant(X))或禁用 sklearn 拦截LogisticRegression(C=1e9,fit_intercept=False)

  • sklearn 返回每个类的概率,所以model_sklearn.predict_proba(X)[:,1] == model_statsmodel.predict(X)

  • 预测功能的使用model_sklearn.predict(X) == (model_statsmodel.predict(X)>0.5).astype(int)

我现在在两个库中看到相同的结果。

另一个区别是您设置了 fit_intercept=False,这实际上是一个不同的模型。您可以看到 Statsmodel 包含截距。没有截距肯定会改变特征的预期权重。试试下面的,看看它是如何比较的:

model = LogisticRegression(C=1e9)