Logistic回归scikit学习系数与统计模型的系数

问题描述 投票:1回答:1

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

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_)

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

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

我想念什么吗?如何产生相似的系数,例如至少在逗号后的一个或两个数字处产生?

python machine-learning scikit-learn logistic-regression statsmodels
1个回答
5
投票

您的代码存在一些问题。

首先,您在此处显示的两个模型是not等效的:尽管您将scikit-learn LogisticRegression设置为fit_intercept=True(这是默认设置),但您并没有这样做statsmodels一;来自statsmodels docs

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

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

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

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

[scikit-learn中无法关闭正则化,但是可以通过将调整参数C设置为较大的值来使其无效。

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

如果为'none'(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()的不同值重复该过程不会改变上面显示的结果的本质。

© www.soinside.com 2019 - 2024. All rights reserved.