Sklearn 和 StatsModels 给出了截然不同的逻辑回归答案
Sklearn and StatsModels give very different logistic regression answers
我正在对一个布尔值 0/1 数据集进行逻辑回归(预测某个年龄给你薪水超过一定数量的概率),我用 sklearn 和 StatsModels 得到非常不同的结果,其中 sklearn 非常错误.
我已将 sklearn 惩罚设置为 None 并将截距项设置为 false 以使函数更类似于 StatsModels,但我看不出如何让 sklearn 给出合理的答案。
灰线是 0 或 1 处的原始数据点,我只是在图中将 1 缩小到 0.1 以便可见。
变量:
# X and Y
X = df.age.values.reshape(-1,1)
X_poly = PolynomialFeatures(degree=4).fit_transform(X)
y_bool = np.array(df.wage.values > 250, dtype = "int")
# Generate a sequence of ages
age_grid = np.arange(X.min(), X.max()).reshape(-1,1)
age_grid_poly = PolynomialFeatures(degree=4).fit_transform(age_grid)
代码如下:
# sklearn Model
clf = LogisticRegression(penalty = None, fit_intercept = False,max_iter = 300).fit(X=X_poly, y=y_bool)
preds = clf.predict_proba(age_grid_poly)
# Plot
fig, ax = plt.subplots(figsize=(8,6))
ax.scatter(X ,y_bool/10, s=30, c='grey', marker='|', alpha=0.7)
plt.plot(age_grid, preds[:,1], color = 'r', alpha = 1)
plt.xlabel('Age')
plt.ylabel('Wage')
plt.show()
sklearn result
# StatsModels
log_reg = sm.Logit(y_bool, X_poly).fit()
preds = log_reg.predict(age_grid_poly)
# Plot
fig, ax = plt.subplots(figsize=(8,6))
ax.scatter(X ,y_bool/10, s=30, c='grey', marker='|', alpha=0.7)
plt.plot(age_grid, preds, color = 'r', alpha = 1)
plt.xlabel('Age')
plt.ylabel('Wage')
plt.show()
StatsModels result
一旦我没有数据集或 scikit-learn 和 statsmodels 的特定版本,我就无法准确地重现结果。但是,我认为您无法成功删除代码中的正则化参数。文档指出您应该传递字符串 'none'
,而不是常量 None
.
请参阅 sklearn.linear_model.LogisticRegression 文档:
penalty{‘l1’, ‘l2’, ‘elasticnet’, ‘none’}, default=’l2’ Used to
specify the norm used in the penalization. The ‘newton-cg’, ‘sag’ and
‘lbfgs’ solvers support only l2 penalties. ‘elasticnet’ is only
supported by the ‘saga’ solver. If ‘none’ (not supported by the
liblinear solver), no regularization is applied.
我认为通过调查系数比使用绘图更容易理解差异。
您可以使用 scikit-learn 模型的 属性 coef_
和 statsmodels 模型的 params
直接调查它。
从逻辑上讲,如果没有正确禁用正则化参数,您应该期望 scikit-learn 模型中的系数较低。
这似乎是因为 sklearn 的实现非常依赖于比例(并且多项式项非常大)。通过首先缩放数据,我得到了定性相同的结果。
# sklearn Model
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
clf = Pipeline([
('scale', StandardScaler()),
('lr', LogisticRegression(penalty='none', fit_intercept=True, max_iter=1000)),
]).fit(X=X_poly, y=y_bool)
preds = clf.predict_proba(age_grid_poly)
# Plot
fig, ax = plt.subplots(figsize=(8,6))
ax.scatter(X ,y_bool/10, s=30, c='grey', marker='|', alpha=0.7)
plt.plot(age_grid, preds[:,1], color = 'r', alpha = 1)
plt.xlabel('Age')
plt.ylabel('Wage')
plt.show()
请注意,在这种情况下我们需要设置 fit_intercept=True
,因为 StandardScaler
会杀死来自 PolynomialFeatures
.[=14= 的常量列(使其全为零) ]
我正在对一个布尔值 0/1 数据集进行逻辑回归(预测某个年龄给你薪水超过一定数量的概率),我用 sklearn 和 StatsModels 得到非常不同的结果,其中 sklearn 非常错误.
我已将 sklearn 惩罚设置为 None 并将截距项设置为 false 以使函数更类似于 StatsModels,但我看不出如何让 sklearn 给出合理的答案。
灰线是 0 或 1 处的原始数据点,我只是在图中将 1 缩小到 0.1 以便可见。
变量:
# X and Y
X = df.age.values.reshape(-1,1)
X_poly = PolynomialFeatures(degree=4).fit_transform(X)
y_bool = np.array(df.wage.values > 250, dtype = "int")
# Generate a sequence of ages
age_grid = np.arange(X.min(), X.max()).reshape(-1,1)
age_grid_poly = PolynomialFeatures(degree=4).fit_transform(age_grid)
代码如下:
# sklearn Model
clf = LogisticRegression(penalty = None, fit_intercept = False,max_iter = 300).fit(X=X_poly, y=y_bool)
preds = clf.predict_proba(age_grid_poly)
# Plot
fig, ax = plt.subplots(figsize=(8,6))
ax.scatter(X ,y_bool/10, s=30, c='grey', marker='|', alpha=0.7)
plt.plot(age_grid, preds[:,1], color = 'r', alpha = 1)
plt.xlabel('Age')
plt.ylabel('Wage')
plt.show()
sklearn result
# StatsModels
log_reg = sm.Logit(y_bool, X_poly).fit()
preds = log_reg.predict(age_grid_poly)
# Plot
fig, ax = plt.subplots(figsize=(8,6))
ax.scatter(X ,y_bool/10, s=30, c='grey', marker='|', alpha=0.7)
plt.plot(age_grid, preds, color = 'r', alpha = 1)
plt.xlabel('Age')
plt.ylabel('Wage')
plt.show()
StatsModels result
一旦我没有数据集或 scikit-learn 和 statsmodels 的特定版本,我就无法准确地重现结果。但是,我认为您无法成功删除代码中的正则化参数。文档指出您应该传递字符串 'none'
,而不是常量 None
.
请参阅 sklearn.linear_model.LogisticRegression 文档:
penalty{‘l1’, ‘l2’, ‘elasticnet’, ‘none’}, default=’l2’ Used to specify the norm used in the penalization. The ‘newton-cg’, ‘sag’ and ‘lbfgs’ solvers support only l2 penalties. ‘elasticnet’ is only supported by the ‘saga’ solver. If ‘none’ (not supported by the liblinear solver), no regularization is applied.
我认为通过调查系数比使用绘图更容易理解差异。
您可以使用 scikit-learn 模型的 属性 coef_
和 statsmodels 模型的 params
直接调查它。
从逻辑上讲,如果没有正确禁用正则化参数,您应该期望 scikit-learn 模型中的系数较低。
这似乎是因为 sklearn 的实现非常依赖于比例(并且多项式项非常大)。通过首先缩放数据,我得到了定性相同的结果。
# sklearn Model
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
clf = Pipeline([
('scale', StandardScaler()),
('lr', LogisticRegression(penalty='none', fit_intercept=True, max_iter=1000)),
]).fit(X=X_poly, y=y_bool)
preds = clf.predict_proba(age_grid_poly)
# Plot
fig, ax = plt.subplots(figsize=(8,6))
ax.scatter(X ,y_bool/10, s=30, c='grey', marker='|', alpha=0.7)
plt.plot(age_grid, preds[:,1], color = 'r', alpha = 1)
plt.xlabel('Age')
plt.ylabel('Wage')
plt.show()
请注意,在这种情况下我们需要设置 fit_intercept=True
,因为 StandardScaler
会杀死来自 PolynomialFeatures
.[=14= 的常量列(使其全为零) ]