class_weight 在 linearSVC 和 LogisticRegression 的损失函数中的作用

Posted

技术标签:

【中文标题】class_weight 在 linearSVC 和 LogisticRegression 的损失函数中的作用【英文标题】:Role of class_weight in loss functions for linearSVC and LogisticRegression 【发布时间】:2015-10-17 21:14:09 【问题描述】:

我试图弄清楚损失函数公式到底是什么,以及在class_weight='auto' 时如何手动计算它,以防svm.svcsvm.linearSVClinear_model.LogisticRegression

对于平衡数据,假设您有一个经过训练的分类器:clf_c。物流损失应该是(我对吗?):

def logistic_loss(x,y,w,b,b0):
    '''
    x: nxp data matrix where n is number of data points and p is number of features.
    y: nx1 vector of true labels (-1 or 1).
    w: nx1 vector of weights (vector of 1./n for balanced data).
    b: px1 vector of feature weights.
    b0: intercept.
    '''
    s = y
    if 0 in np.unique(y):
        print 'yes'
        s = 2. * y - 1
    l = np.dot(w, np.log(1 + np.exp(-s * (np.dot(x, np.squeeze(b)) + b0))))
    return l

我意识到logisticRegression 有predict_log_proba(),它在数据平衡时为您提供准确的信息:

b, b0 = clf_c.coef_, clf_c.intercept_
w = np.ones(len(y))/len(y)
-(clf_c.predict_log_proba(x[xrange(len(x)), np.floor((y+1)/2).astype(np.int8)]).mean() == logistic_loss(x,y,w,b,b0)

注意,np.floor((y+1)/2).astype(np.int8) 只是将 y=(-1,1) 映射到 y=(0,1)。

但这在数据不平衡时不起作用。

此外,您希望分类器(此处为logisticRegression)在数据平衡和class_weight=None 与数据不平衡和class_weight='auto' 时表现相似(就损失函数值而言)。我需要有一种方法来计算两种场景的损失函数(没有正则化项)并进行比较。

简而言之,class_weight = 'auto'究竟是什么意思?它是指class_weight = -1 : (y==1).sum()/(y==-1).sum() , 1 : 1. 还是class_weight = -1 : 1./(y==-1).sum() , 1 : 1./(y==1).sum()

非常感谢任何帮助。我尝试浏览源代码,但我不是程序员,我被卡住了。 提前非常感谢。

【问题讨论】:

【参考方案1】:

class_weight启发式

我对您对class_weight='auto' 启发式的第一个提议感到有些困惑,因为:

class_weight = -1 : (y == 1).sum() / (y == -1).sum(), 
                1 : 1.

如果我们对其进行归一化以使权重总和为 1,则与您的第二个命题相同。

无论如何要了解class_weight="auto" 的作用,请参阅以下问题: what is the difference between class weight = none and auto in svm scikit learn.

我复制到这里供以后比较:

这意味着您拥有的每个班级(在班级中)的权重都相等 为 1 除以该类在您的数据中出现的次数 (y),因此出现频率更高的类将获得更低的权重。这是 然后进一步除以所有反类频率的平均值。

请注意这不是很明显;)。

此启发式已弃用,将在 0.18 中删除。它将被另一个启发式算法class_weight='balanced' 取代。

“平衡”启发式方法按与频率倒数成比例的方式对类进行加权。

来自文档:

“平衡”模式使用 y 的值来自动调整 权重与输入数据中的类频率成反比: n_samples / (n_classes * np.bincount(y)).

np.bincount(y) 是一个数组,其中元素 i 是第 i 类样本的计数。

这里有一些代码来比较两者:

import numpy as np
from sklearn.datasets import make_classification
from sklearn.utils import compute_class_weight

n_classes = 3
n_samples = 1000

X, y = make_classification(n_samples=n_samples, n_features=20, n_informative=10, 
    n_classes=n_classes, weights=[0.05, 0.4, 0.55])

print("Count of samples per class: ", np.bincount(y))
balanced_weights = n_samples /(n_classes * np.bincount(y))
# Equivalent to the following, using version 0.17+:
# compute_class_weight("balanced", [0, 1, 2], y)

print("Balanced weights: ", balanced_weights)
print("'auto' weights: ", compute_class_weight("auto", [0, 1, 2], y))

输出:

Count of samples per class:  [ 57 396 547]
Balanced weights:  [ 5.84795322  0.84175084  0.60938452]
'auto' weights:  [ 2.40356854  0.3459682   0.25046327]

损失函数

现在真正的问题是:这些权重如何用于训练分类器?

很遗憾,我在这里没有完整的答案。

对于SVClinearSVC,文档字符串非常清晰

对于 SVC,将第 i 类的参数 C 设置为 class_weight[i]*C。

如此高的权重意味着该类的正则化程度较低,而 svm 对其进行正确分类的动机更高。

我不知道他们如何处理逻辑回归。我会尝试研究它,但大部分代码都在 liblinear 或 libsvm 中,我对它们不太熟悉。

但是,请注意class_weight中的权重不会直接影响predict_proba等方法。它们会更改其输出,因为分类器优化了不同的损失函数。 不确定这是否清楚,所以这里有一个 sn-p 来解释我的意思(您需要为导入和变量定义运行第一个):

lr = LogisticRegression(class_weight="auto")
lr.fit(X, y)
# We get some probabilities...
print(lr.predict_proba(X))

new_lr = LogisticRegression(class_weight=0: 100, 1: 1, 2: 1)
new_lr.fit(X, y)
# We get different probabilities...
print(new_lr.predict_proba(X))

# Let's cheat a bit and hand-modify our new classifier.
new_lr.intercept_ = lr.intercept_.copy()
new_lr.coef_ = lr.coef_.copy()

# Now we get the SAME probabilities.
np.testing.assert_array_equal(new_lr.predict_proba(X), lr.predict_proba(X))

希望这会有所帮助。

【讨论】:

感谢您的回复,感谢您对重量的详尽解释!所以根据第一个版本: w0 = 2*n_1 / (n_0+n_1) 和 w1=2*n_0/(n_0+n_1) 其中 w0 是第 0 类的权重,n_0 是第 0 类中的样本数,n_​​1 是数字1 类中的样本。超级奇怪的启发式。也许我没有清楚地理解某些东西,但是您引用的较新版本也具有相同的权重(至少对于二进制情况)。我还发现这个讨论可能对其他读者也有帮助:github.com/scikit-learn/scikit-learn/issues/4324 我明白了。加权方案未包含在predict_proba()predict_log_proba() 中。 :'-( 但也许我可以这样合并它:loss_imbalanced = loss_balanced[indices_of_class_0] * w0 + loss_balanced[indices_of_class_1] * w1。我会试试这个并发布结果。 别难过 ;)。请注意,即使是二进制情​​况,“平衡”启发式也是不同的。考虑y=[0, 0, 1],你会得到:auto: [ 0.66666667 1.33333333]balanced: [ 0.75 1.5 ]。至于predict_(log_)proba(),将函数包装成使用权重的东西是相当简单的。

以上是关于class_weight 在 linearSVC 和 LogisticRegression 的损失函数中的作用的主要内容,如果未能解决你的问题,请参考以下文章

在 sklearn RandomForestClassifier 中,class_weight=None 是不是等同于 class_weight="balanced_subsample&qu

class_weights 或加权损失在哪里惩罚网络?

如何在 sklearn 0.14 版中设置“class_weight”?

为啥 LinearSVC 在这个数据集上效果这么差?

sklearn:评估 LinearSVC AUC

Keras:one-hot 编码的类权重(class_weight)