scikit-learn LogisticRegression与statsmodels smf.logit结果差异原因问询
差异成因及解决方法
核心成因1:参数返回维度不匹配
statsmodels通过公式default_01 ~ income + balance构建模型时默认包含截距项,返回的lr.params为3个参数,顺序为[截距项, income系数, balance系数]。而scikit-learn的logit.coef_仅返回两个输入特征的系数,截距项单独存储在logit.intercept_属性中,若对比时未对齐参数顺序和维度,会直接出现量级层面的偏差。
核心成因2:特征尺度差异导致求解器收敛不完全
Default数据集中income的取值范围(约100070000)远大于`balance`的取值范围(约03000),特征尺度差异极大。scikit-learn的LogisticRegression默认使用lbfgs求解器,默认收敛阈值tol=1e-4对于未标准化的特征来说宽松度过高,即便你设置C=1e9关闭了L2正则化,求解器也会在未达到全局最优时提前停止迭代,导致系数偏差。
而statsmodels的logit模型默认使用牛顿迭代法求解,针对广义线性模型的优化特性做了适配,对未标准化特征的鲁棒性更好,能收敛到更准确的参数值。
核心成因3:损失函数实现的微小差异
scikit-learn的逻辑回归实现默认会对损失函数做平均(除以样本量),statsmodels的实现则直接计算原始对数似然值,理论上当正则化完全关闭时二者的最优解一致,但实际迭代过程中会导致收敛路径产生差异,进一步放大未标准化特征带来的偏差。
修正方案
调整scikit-learn侧的调用逻辑,更换求解器、收紧收敛阈值,同时对齐参数返回顺序,即可获得和statsmodels几乎一致的结果:
def boot_fn2(data): X = data[['income', 'balance']] y = data.default_01 # 更换牛顿迭代求解器,收紧收敛阈值 logit = LogisticRegression(C = 1e9, solver='newton-cg', tol=1e-8) logit.fit(X, y) # 返回顺序和statsmodels对齐:截距、income系数、balance系数 return np.hstack([logit.intercept_, logit.coef_[0]])
也可以选择在拟合前对两个输入特征做标准化处理,原始求解器也能收敛到准确结果。
内容的提问来源于stack exchange,提问作者Link

