为什么 sklearn 中逻辑回归的等效 class_weights 会产生不同的结果?
Why the equivalent class_weights for Logistic Regression in sklearn generates different outcomes?
在处理不平衡数据集时,我在 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
?
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)
对于 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]]
在处理不平衡数据集时,我在 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
?
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)
对于 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]]