机器学习之不平衡数据集处理方法


一、不平衡数据集

1、不平衡数据集定义

不平衡数据集指的是数据集各个类别的样本数目相差巨大。以二分类问题为例,假设正类的样本数量远大于负类的样本数量,这种情况下的数据称为不平衡数据。

2、不平衡数据集举例

  1. 在二分类问题中,训练集中class 1的样本数比上class 2的样本数的比值为60:1。使用逻辑回归进行分类,最后结果是其忽略了class 2,将所有的训练样本都分类为class 1。
  2. 在三分类问题中,三个类别分别为A,B,C,训练集中A类的样本占70%,B类的样本占25%,C类的样本占5%。最后我的分类器对类A的样本过拟合了,而对其它两个类别的样本欠拟合。

3、不平衡数据集实例

训练数据不均衡是常见并且合理的情况,比如:

  • 在欺诈交易识别中,绝大部分交易是正常的,只有极少部分的交易属于欺诈交易。
  • 在客户流失问题中,绝大部分的客户是会继续享受其服务的(非流失对象),只有极少数部分的客户不会再继续享受其服务(流失对象)。

4、不平衡数据集导致的问题

如果训练集的90%的样本是属于同一个类的,而我们的分类器将所有的样本都分类为该类,在这种情况下,该分类器是无效的,尽管最后的分类准确度为90%。所以在数据不均衡时,准确度(Accuracy)这个评价指标参考意义就不大了。实际上,如果不均衡比例超过4:1,分类器就会偏向于大的类别。

5、不平衡数据集的主要处理方法

  1. 从数据的角度出发,主要方法为采样,分为欠采样过采样以及对应的一些改进方法。
  2. 从算法的角度出发,考虑不同误分类情况代价的差异性对算法进行优化,主要是基于​代价敏感学习算法​(Cost-Sensitive Learning),代表的算法有adacost。

另外可以将不平衡数据集的问题考虑为一分类(One Class Learning)或者异常检测(Novelty Detection)问题,代表的算法有One-class SVM。

从数据角度出发的不平衡数据集的处理方法对应的python库(imblearn)

不平衡数据的学习即需要在分布不均匀的数据集中学习到有用的信息。

二、不平衡(均衡)数据集常用的处理方法

1、扩充数据集

首先想到能否获得更多数据,尤其是小类(该类样本数据极少)的数据,更多的数据往往能得到更多的分布信息。

2、对数据集进行重采样

(1)过采样(over-sampling)

对小类的数据样本进行过采样来增加小类的数据样本个数,即采样的个数大于该类样本的个数。

# -*- coding: utf-8 -*-
from imblearn.over_sampling import RandomOverSampler
ros=RandomOverSampler(random_state=0) #采用随机过采样(上采样)
x_resample,y_resample=ros.fit_sample(trainset,labels)

(2)欠采样(under-sampling)

对大类的数据样本进行欠采样来减少大类的数据样本个数,即采样的个数少于该类样本的个数。

采样算法容易实现,效果也不错,但可能增大模型的偏差(Bias),因为放大或者缩小某些样本的影响相当于改变了原数据集的分布。对不同的类别也要采取不同的采样比例,但一般不会是1:1,因为与现实情况相差甚远,压缩大类的数据是个不错的选择。

# -*- coding: utf-8 -*-
from imblearn.under_sampling import RandomUnderSampler
# 通过设置RandomUnderSampler中的replacement=True参数, 可以实现自助法(boostrap)抽样
# 通过设置RandomUnderSampler中的rratio参数,可以设置数据采样比例
rus=RandomUnderSampler(ratio=0.4,random_state=0,replacement=True) #采用随机欠采样(下采样)
x_resample,y_resample=rus.fit_sample(trainset,labels)

3、人造数据

(1)属性值随机采样

在该类下所有样本的每个属性特征的取值空间中随机选取一个组成新的样本,即属性值随机采样。此方法多用于小类中的样本,不过它可能破坏原属性的线性关系。如在图像中,对一幅图像进行扭曲得到另一幅图像,即改变了原图像的某些特征值,但是该方法可能会产生现实中不存在的样本。

(2)SMOTE(Synthetic Minority Over-sampling Technique)

SMOTE是一种过采样算法,它构造新的小类样本而不是产生小类中已有的样本的副本。它基于距离度量选择小类别下两个或者更多的相似样本,然后选择其中一个样本,并随机选择一定数量的邻居样本对选择的那个样本的一个属性增加噪声,每次处理一个属性。这样就构造了许多新数据。

4、改变分类算法

  1. 使用代价函数时,可以增加小类样本的权值,降低大类样本的权值(这种方法其实是产生了新的数据分布,即产生了新的数据集),从而使得分类器将重点集中在小类样本身上。刚开始,可以设置每个类别的权值与样本个数比例的倒数,然后可以使用过采样进行调优。
  2. 可以把小类样本作为异常点(outliers),把问题转化为异常点检测问题(anomaly detection)。此时分类器需要学习到大类的决策分界面,即分类器是一个单个类分类器(One Class Classifier)。
  3. 由Robert E. Schapire提出的”The strength of weak learnability”方法,该方法是一个boosting算法,它递归地训练三个弱学习器,然后将这三个弱学习器结合起形成一个强的学习器。

三、将数据集划分为训练数据集和测试数据集

# -*- coding: utf-8 -*-
from collections import Counter
from sklearn.model_selection import train_test_split  #数据集划分
# 参数test_size表示数据集和测试集的划分比例
x_train,x_test,y_train,y_test = train_test_split(datasets,labels,test_size=0.1,random_state=0) #数据集划分
print(len(x_train))
print(len(x_test))
print(Counter(x_train))#统计训练集中不同类别的数量

四、使用K折交叉验证评估模型性能

1、K折交叉验证

在k折交叉验证中,我们不重复地随机将训练数据集划分为k个,其中k-1个用于​模型的训练​,剩余的1个用于​测试​。重复此过程k次,我们就得到了k个模型及对模型性能的评价。

k折交叉验证的一个特例就是​留一(leave-one-out,LOO)交叉验证法​。在LOO中,我们将数据子集划分的数量等同于样本数(k=n),这样每次只有一个样本用于测试。当数据集非常小时,建议使用此方法进行验证。

# -*- coding: utf-8 -*-
from sklearn.model_selection import KFold   #交叉验证
import numpy as np
kf=KFold(n_splits=10)
for train_index,test_index in kf.split(datasets,labels):
    x_train = np.array(datasets)[train_index]
    y_train = np.array(datasets)[train_index]
    x_test = np.array(datasets)[test_index]
    y_test = np.array(labels)[test_index]

2、分层K折交叉验证

分层k折交叉验证对标准k折交叉验证做了稍许改进,它可以获得偏差和方差都较低的评估结果,特别是类别比例相差较大时。在分层交叉验证中,类别比例在每个分块中得以保持,这使得每个分块中的类别比例与训练数据集的整体比例一致。

# -*- coding: utf-8 -*-
from sklearn.model_selection import StratifiedKFold #分层k折交叉验证
import numpy as np
kf = StratifiedKFold(n_splits=10, shuffle=True)
for train_index, test_index in kf.split(datasets, labels):
    x_train = np.array(datasets)[train_index]
    y_train = np.array(datasets)[train_index]
    x_test = np.array(datasets)[test_index]
    y_test = np.array(labels)[test_index]

  目录