为啥 sklearn 中逻辑回归的等效 class_weights 会产生不同的结果?

Posted

技术标签:

【中文标题】为啥 sklearn 中逻辑回归的等效 class_weights 会产生不同的结果?【英文标题】:Why the equivalent class_weights for Logistic Regression in sklearn generates different outcomes?为什么 sklearn 中逻辑回归的等效 class_weights 会产生不同的结果? 【发布时间】:2021-12-19 12:40:56 【问题描述】:

在处理不平衡数据集时,我在 scikit-learn 中发现了一个关于 LogisticRegression 的有趣问题。

对于参数class_weight,如果我发送1:0.5, 0:0.5,我将与1:1, 0:1 得到不同的结果,即使它们在数学上实际上是相同的权重。

这是我得到的,

import numpy as np
from sklearn.linear_model import LogisticRegression
np.random.seed(1)

def sigmoid(x):
    return 1/(np.exp(-x)+1)

x1 = np.random.normal(0, 4, 100000)
x2 = np.random.normal(0, 1, 100000)
X = np.array([x1, x2]).T

proba = sigmoid(0.1 + 2*x1 + 3*x2)
y = np.random.binomial(1, proba)

lr1 = LogisticRegression(C=1, class_weight = 1:0.5, 0:0.5).fit(X, y)
print(lr1.score(X,y)) # 0.93656

lr2 = LogisticRegression(C=1, class_weight = 0:1, 1:1).fit(X, y)
print(lr2.score(X,y)) # 0.93653
能否告诉我class_weight 参数的实际工作原理以及它发生的原因? 如何正确设置class_weight

【问题讨论】:

【参考方案1】:

class_weight 的实现方式是它会影响 sample_weight,另一方面,这些会乘以损失。不幸的是,它们不会影响正则化器,因此它的相对强度会发生变化

lr2 = LogisticRegression(C=0.5, class_weight = 0:1, 1:1).fit(X, y)

会给你想要的

print(lr2.score(X,y)) # 0.93656

类似

lr2 = LogisticRegression(C=0.25, class_weight = 0:2, 1:2).fit(X, y)
print(lr2.score(X,y)) # 0.93656

所以一般来说 1/C(正则化强度)应该等于你重新加权的权重总和,因为它模糊地被实现为

LOSS := 1/C ||w||^2 + SUM_i sample_weight_i loss(pred(x_i), y_i)

【讨论】:

【参考方案2】:

对于LogisticRegression,默认设置为penalty='l2'。见help page。如果penalty='none' ,您只会获得相同重量的相同结果:

lr1 = LogisticRegression(C=1, class_weight = 1:0.5, 0:0.5 , penalty='none').fit(X, y)
print(lr1.score(X,y)) 

lr2 = LogisticRegression(C=1, class_weight = 0:1, 1:1,penalty='none').fit(X, y)
print(lr2.score(X,y)) 

0.93652
0.93652

正如post 和上面提到的 LogisticRegression 帮助页面所提到的,更大的正则化(或更小的 C)将使系数(和结果)更相似:

lr1 = LogisticRegression(C=100, class_weight = 1:0.5, 0:0.5 , penalty='l2').fit(X, y)
print(lr1.coef_)

lr2 = LogisticRegression(C=100, class_weight = 0:1, 1:1,penalty='l2').fit(X, y)
print(lr2.coef_)

[[2.00034043 2.98401278]]
[[2.00035828 2.98404571]]

相比:

lr1 = LogisticRegression(C=0.1, class_weight = 1:0.5, 0:0.5 , penalty='l2').fit(X, y)
print(lr1.coef_)

lr2 = LogisticRegression(C=0.1, class_weight = 0:1, 1:1,penalty='l2').fit(X, y)
print(lr2.coef_)

[[1.96628865 2.9210898 ]]
[[1.98293929 2.95188187]]

【讨论】:

以上是关于为啥 sklearn 中逻辑回归的等效 class_weights 会产生不同的结果?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 sklearn 逻辑回归正则化权重和截距?

为啥 auc 与 sklearn 和 R 的逻辑回归如此不同

class_weights 如何应用于 sklearn 逻辑回归?

Sklearn实现逻辑回归

获取 sklearn 逻辑回归的边际效应

sklearn 逻辑回归中的特征