不均衡分类问题 之 class weight & sample weight

分类问题中,当不同类别的样本量差异很大,即类分布不平衡时,很容易影响分类结果。因此需要进行校正。

sklearn的做法是加权,加权就要涉及到class_weight和sample_weight,当不设置该参数时,默认所有类别的权值为1。

类型权重 class_weight

字典类型,将类索引映射到权重值。对训练集里的每个类别加权,作用于损失函数(仅在训练过程中)。从而使模型更加关注样本数量少的类别。如果某类别的样本数多,那么它的权重就低,反之则权重就高.

应用场景
第一种是误分类的代价很高。比如对合法用户和非法用户进行分类,将非法用户分类为合法用户的代价很高,我们宁愿将合法用户分类为非法用户,这时可以人工再甄别,但是却不愿将非法用户分类为合法用户。这时,我们可以适当提高非法用户的权重class_weight={0:0.9, 1:0.1}。

第二种是样本是高度失衡的,比如我们有合法用户和非法用户的二元样本数据10000条,里面合法用户有9995条,非法用户只有5条,如果我们不考虑权重,则我们可以将所有的测试集都预测为合法用户,这样预测准确率理论上有99.95%,但是却没有任何意义。这时,我们可以选择balanced(scikit-learn 逻辑回归类库使用小结),让类库自动提高非法用户样本的权重。

参数设置
那么应该如何设置class_weight呢?

  1. 通过字典形式传入权重参数,如二分类问题 y ∈ { 0 , 1 } y \in \{0,1\} y{ 0,1},class_weight={0:0.9, 1:0.1}
  2. 设置class_weight = 'balanced’
    此时,会自动调用from sklearn.utils.class_weight import compute_class_weight计算权重,平衡输入样本中各类别之间的权重。其计算公式为:
    w e i g h t = n _ s a m p l e s / ( n _ c l a s s e s ∗ n p . b i n c o u n t ( y ) ) weight = n\_samples / (n\_classes * np.bincount(y)) weight=n_samples/(n_classesnp.bincount(y))
import numpy as np

y = [0,0,0,0,0,0,0,0,1,1,1,1,1,1,2,2]  #标签值,一共16个样本

a = np.bincount(y)  # array([8, 6, 2], dtype=int64) 计算每个类别的样本数量
aa = 1/a  #倒数 array([0.125     , 0.16666667, 0.5       ])
print(aa)

from sklearn.utils.class_weight import compute_class_weight 
class_weight = 'balanced'
classes = np.array([0, 1, 2])  #标签类别
weight = compute_class_weight(class_weight, classes, y)
print(weight) # [0.66666667 0.88888889 2.66666667]

print(0.66666667*8)  #5.33333336
print(0.88888889*6)  #5.33333334
print(2.66666667*2) #5.33333334
# 这三个值非常接近
# 'balanced'计算出来的结果很均衡,使得惩罚项和样本量对应

这种方式在原始的损失函数的基础上乘以对应的sample_weight来计算最终的损失。这样计算而来的损失函数不会因为样本不平衡而被“推向”样本量偏少的类别中

样本权重 sample_weight

numpy权重数组。对每个样本加权(仅在训练过程中),思路和类别权重类似,即样本数多的类别样本权重低,反之样本权重高

应用场景
样本不平衡,导致样本不是总体样本的无偏估计,从而可能导致我们的模型预测能力下降。遇到这种情况,我们可以通过调节样本权重来尝试解决这个问题。调节样本权重的方法有两种,第一种是在class_weight使用balanced。第二种是在调用fit函数时,通过sample_weight来自己调节每个样本权重。

注意事项:

  1. 在sklearn中的逻辑回归时,如果上面两种方法都用到了,那么样本的真正权重是class_weight * sample_weight.
    原理:样本或类别的权重在训练模型最终通过损失函数实现(以逻辑回归为例):
    算法会把每个样本的训练损失乘以它的权重class_weight*sample_weight,损失函数为:

    J ( θ ) = − β ∗ ln ⁡ ( θ ) = − β ∑ i = 1 m ( y ( i ) l o g ( h θ ( x ( i ) ) ) + ( 1 − y ( i ) ) l o g ( 1 − h θ ( x ( i ) ) ) ) J(\theta) =-\beta*\ln(\theta) = −\beta∑_{i=1}^m(y^{(i)}log(h_θ(x^{(i)}))+(1−y^{(i)})log(1−h_θ{(x^{(i)})})) J(θ)=βln(θ)=βi=1m(y(i)log(hθ(x(i)))+(1y(i))log(1hθ(x(i))))

    其中, β = ( c l a s s _ w e i g h t ∗ s a m p l e _ w e i g h t ) \beta = (class\_weight∗sample\_weight) β=(class_weightsample_weight)

    应用:做受众选择(人群扩展、人群定向)模型,若种子包括目标商品转化和行为用户(购买较少,加入线上加购、收藏作为正样本),可考虑加大转化用户的样本权重。

  2. 如果仅仅是类不平衡,则使用class_weight;
    如果类内样本之间还不平衡,则使用sample_weights。

  3. 如果class_weight选择balanced,那么类库会根据训练样本量来计算权重。某种类型样本量越多,则权重越低,样本量越少,则权重越高。

猜你喜欢

转载自blog.csdn.net/SkullSky/article/details/106222795
今日推荐