分类类别不平衡问题

一、什么是类不平衡

在分类中经常会遇到:某些类别数据特别多,某类或者几类数据特别少。如二分类中,一种类别(反例)数据特别多,另一种类别(正例)数据少的可怜。如银行欺诈问题,客户流失问题,电力盗窃以及罕见疾病识别等都存在着数据类别不均衡的情况。

二、为什么要对类不平衡进行特殊处理

传统的分类算法旨在最小化分类过程中产生的错误数量。它们假设假阳性(实际是反例,但是错分成正例)和假阴性(实际是正例,但是错分为反例)错误的成本是相等的,因此不适合于类不平衡的数据。

有研究表明,在某些应用下,1∶35的比例就会使某些分类方法无效,甚至1∶10的比例也会使某些分类方法无效。如果数据存在严重的不平衡,预测得出的结论往往也是有偏的,即分类结果会偏向于较多观测的类。

三、提升不平衡类分类准确率的方法

提升不平衡类分类准确率的方法有三大类:采样、阈值移动、调整代价或权重。

1、采样

1.1 过采样

过采样基本思想就是通过改变训练数据的分布来消除或减小数据的不平衡。过采样有随机过采样、基于聚类的过采样、信息性过采样(SMOTE)三大类方法。
随机过采样:通过增加少数类样本来提高少数类的分类性能 ,最简单的办法是随机复制少数类样本。

基于聚类的过采样:K-Means聚类算法独立地被用于少数和多数类实例,之后,每个聚类都过采样使得相同类的所有聚类有着同样的实例数量。

信息性过采样--SMOTE
利用KNN技术,对于少数类样本a, 随机选择一个最近邻的样本b, 然后从a与b的连线上随机选取一个点c作为新的少数类样本。

SMOTE有时能提升分类准确率,有时不能,甚至可能因为构建数据时放大了噪声数据导致分类结果变差,这要视具体情况而定。

1.2 欠采样

欠采样方法通过减少多数类样本来提高少数类的分类性能。
随机欠采样:通过随机地去掉一些多数类样本来减小多数类的规模。

集成技术:欠采样中的算法集成技术是利用集成学习机制,将反例划分为若干个集合供不同学习器使用,这样对每个学习器来看都进行了欠采样,但在全局来看却不会丢失重要信息,一般适用于数据集足够大的情况。这里的集成技术可以分为基于Bagging的方法和基于Boosting的方法。

2、 阈值移动法

许多模型的输出类别是基于阈值的,例如逻辑回归中小于0.5的为反例,大于则为正例。在数据不平衡时,默认的阈值会导致模型输出倾向于类别数据多的类别。阈值移动是通过改变决策阈值来偏重少数类。

3 、调整代价或权重法

通过调整不同类类的代价或权重来偏重少数类以改进分类性能。

四、方法评价

方法 优点 缺点
随机过采样 不会造成信息缺失,表现优于欠采样 过采样会引起噪声数据的权重过大,也会加大过拟合的可能性
基于聚类的过采样 有助于克服类之间不平衡,有助于克服由不同子聚类组成的类之间的不平衡 可能造成过拟合
信息性过采样SMOTE 缓解过拟合,不会损失有价值信息 对高维数据不是很有效;当生成合成性实例时,不会把来自其他类的相邻实例考虑进来,这会导致类重叠的增加,引入额外的噪音
随机欠采样 减少运行时间,并且当数据集很大时,可以通过减少样本数量来解决存储问题 可能会丢失重要信息,采样后的数据不一定能代表全部数据,导致分类结果不精准
集成技术 不会造成信息缺失 运行耗时,占内存,要求数据集足量大
阈值移动 不会造成信息缺失,过拟合的可能性小 很难建立参数与不平衡分类精度间的定量关系,不能准确处理不平衡数据
调整代价或权重 不会造成信息缺失,过拟合的可能性小 很难建立参数与不平衡分类精度间的定量关系,不能准确处理不平衡数据

五、实际案例

案例:信用卡欺诈

案列介绍:数据集由欧洲持卡人于2013年9月使用信用卡进行交易的数据。此数据集显示两天内发生的交易,其中284,807笔交易中有492笔被盗刷。数据集非常不平衡,被盗刷占所有交易的0.172%。

由于保密问题,数据只包含作为PCA转换结果的数字输入变量V1,V2,... V28,没有用PCA转换的唯一特征是“时间”和“量”。特征‘时间‘包含数据集中每个事务和第一个事务之间经过的秒数,特征“金额”是交易金额,特征‘类‘是响应变量,如果发生被盗刷,则取值1,否则为0。

尝试了多种方法,以此数据案例结果来看,法二XGboost模型比较好,当然最优结果不止局限于此,大家可以尝试其它方法优化结果
法一:SMOTE算法、LR模型以及阈值移动的方法

import pandas as pd
import numpy as np
from sklearn.metrics import recall_score,confusion_matrix
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import KFold
import itertools
import warnings
warnings.filterwarnings("ignore")

#读取信用卡数据
data = pd.read_csv("creditcard.csv",encoding='utf-8')

# 数据归一化
from sklearn.preprocessing import StandardScaler
data['normAmount'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1, 1))

#数据划分成LABEL列和特征列
X_data = data.drop(['Class','Time','Amount'],axis = 1)  #删除LABEL及其它非特征列
y = data.Class

#查看样本类别分布
from collections import Counter
print(Counter(y))

#更直观地,可以绘制饼图
import matplotlib.pyplot as plt
plt.axes(aspect='equal')
counts = data.Class.value_counts() #统计LABEL中各类别的频数
plt.pie(x = counts, #绘制数据
        labels = pd.Series(counts.index).map({0:'normal',1:'cheat'}),  #添加文字标签
        autopct='%.2f%%'    #设置百分比的格式,这里保留两位小数
        )
plt.show()  #显示图形

#数据划分成训练集和测试集
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X_data,y,test_size=0.3) 

#==================解决类别不均衡问题,SMOTE算法==========================
from imblearn.over_sampling import SMOTE
sm = SMOTE(random_state=123)
X_train_sm, y_train_sm = sm.fit_sample(X_train, y_train)

#查看过采样之后的类别分布
print(Counter(y_train_sm))

#========================逻辑回归模型=====================================
X_train_sm = pd.DataFrame(X_train_sm)
y_train_sm = pd.DataFrame(y_train_sm)
# 指定不同的惩罚系数,利用交叉验证找到最合适的参数,打印每个结果
def printing_Kfold_scores(X_train_data,Y_train_data):
    fold = KFold(5,shuffle=False)
    print(fold)
    c_param_range = [0.01,0.1,1,10,100]

    results_table = pd.DataFrame(index=range(len(c_param_range),2),
                                 columns=['C_Parameter','Mean recall score'])
    results_table['C_Parameter'] = c_param_range
    j=0
    for c_param in c_param_range:
        print('c_param:',c_param)
        recall_accs = []
        for iteration,indices in enumerate(fold.split(X_train_data)):
            lr = LogisticRegression(C = c_param, penalty = 'l1')
            lr.fit(X_train_data.iloc[indices[0],:],
                   Y_train_data.iloc[indices[0],:].values.ravel())
            Y_pred = lr.predict(X_train_data.iloc[indices[1],:].values)

            recall_acc = recall_score(Y_train_data.iloc[indices[1],:].values,Y_pred)
            recall_accs.append(recall_acc)

            print ('Iteration:',iteration,'recall_acc:',recall_acc)

        print ('Mean recall score',np.mean(recall_accs))
        results_table.loc[j,'Mean recall score'] = np.mean(recall_accs)
        print('----------')
        j+=1
    print(type(results_table['Mean recall score']))
    print(results_table['Mean recall score'])
    results_table['Mean recall score'] = results_table[
        'Mean recall score'].astype('float64')

    best_c = results_table.loc[results_table[
        'Mean recall score'].idxmax()]['C_Parameter']
    print ('best_c is :',best_c)
    return best_c

#绘制混淆矩阵图
def plot_confusion_matrix(cm, classes,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):

    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=0)
    plt.yticks(tick_marks, classes)

    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, cm[i, j],
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

best_c = printing_Kfold_scores(X_train_sm,y_train_sm)
lr = LogisticRegression(C = best_c, penalty = 'l2')
lr.fit(X_train_sm,y_train_sm.values.ravel())
y_pred = lr.predict_proba(X_test.values)

#==============================阈值移动方法=========================
#默认阈值一般为0.5
thresholds = [0.5,0.6,0.7,0.8,0.9]
plt.figure(figsize=(10,10))

m = 1
for i in thresholds:
    y_test_predictions_high_recall = y_pred[:,1] > i

    plt.subplot(3,3,m)
    m += 1

    cnf_matrix = confusion_matrix(y_test,y_test_predictions_high_recall)
    np.set_printoptions(precision=2)

    print ("Recall:{}".format(cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1])))

    class_names = [0,1]
    plot_confusion_matrix(cnf_matrix
                          , classes=class_names
                          , title='Threshold >= %s'%i) 

混淆矩阵如下所示

法二:算法集成技术XGBoost

import pandas as pd
import numpy as np
from sklearn.metrics import accuracy_score,classification_report,roc_curve,auc,confusion_matrix
import itertools
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")

#读取信用卡数据
data = pd.read_csv("creditcard.csv",encoding='utf-8')   #文末附有数据

# 数据归一化
from sklearn.preprocessing import StandardScaler
data['normAmount'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1, 1))

data = data.drop(['Time','Amount'],axis = 1)
#数据划分成LABEL列和特征列
X_data = data.drop(['Class'],axis = 1)  #删除LABEL及其它非特征列
y = data.Class

#查看样本类别分布
from collections import Counter
print(Counter(y))
# Counter({0: 37027, 1: 227})

#更直观地,可以绘制饼图
plt.axes(aspect='equal')
counts = data.Class.value_counts() #统计LABEL中各类别的频数
plt.pie(x = counts, #绘制数据
        labels = pd.Series(counts.index).map({0:'normal',1:'cheat'}),  #添加文字标签
        autopct='%.2f%%'    #设置百分比的格式,这里保留两位小数
        )
plt.show()  #显示图形

from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X_data,y,test_size=0.3,random_state=123)
Train,Test = train_test_split(data,test_size=0.3,random_state=123) 

#=========================XGBoost模型分类======================
import xgboost
xgb = xgboost.XGBClassifier()   #添加系数scale_pos_weight=10或100即为调整类别的权重,与阈值移动效果类似
# 使用非平衡的训练数据集拟合模型
xgb.fit(X_train,y_train)
# 基于拟合的模型对测试数据集进行预测
y_pred = xgb.predict(X_test)
# 返回模型的预测效果
print('模型的准确率为:\n',accuracy_score(y_test, y_pred))
print('模型的评估报告:\n',classification_report(y_test, y_pred))
# 计算用户流失的概率值
y_score = xgb.predict_proba(X_test)[:,1]
fpr,tpr,threshold = roc_curve(y_test, y_score)
# 计算AUC的值
roc_auc = auc(fpr,tpr)
print('ROC curve (area = %0.2f)' % roc_auc)

y_pred_proba = xgb.predict_proba(X_test) #之后阈值移动要用到

#绘制混淆矩阵图
def plot_confusion_matrix(cm, classes,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):

    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=0)
    plt.yticks(tick_marks, classes)

    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, cm[i, j],
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

#==============================阈值移动方法===================================
#默认阈值一般为0.5
thresholds = [0.45,0.47,0.49,0.51,0.53,0.55]
plt.figure(figsize=(10,10))

m = 1
for i in thresholds:
    y_test_predictions_high_recall = y_pred_proba[:,1] > i

    plt.subplot(3,3,m)
    m += 1

    cnf_matrix = confusion_matrix(y_test,y_test_predictions_high_recall)
    np.set_printoptions(precision=2)

    print ("Recall:{}".format(cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1])))

    class_names = [0,1]
    plot_confusion_matrix(cnf_matrix
                          , classes=class_names
                          , title='Threshold >= %s'%i) 

混淆矩阵如下所示

期间安装imblearn包出现的小插曲:

conda和pip都报错,将安装语句改为:conda install -c glemaitre imbalanced-learn 安装 成功

参考资料:

https://github.com/wangjiang0624/Note/blob/master/MachineLearning/分类类别不平衡.md

https://www.jiqizhixin.com/articles/2017-03-20-8

https://www.kaggle.com/mlg-ulb/creditcardfraud

原文地址:https://www.cnblogs.com/shenggang/p/12133016.html

时间: 2024-10-09 19:31:14

分类类别不平衡问题的相关文章

机器学习-类别不平衡问题

引言:我们假设有这种情况,训练数据有反例998个,正例2个,模型是一个永远将新样本预测为反例的学习器,就能达到99.8%的精度,这样显然是不合理的. 类别不平衡:分类任务中不同类别的训练样例数差别很大. 一般我们在训练模型时,基于样本分布均匀的假设.从线性分类器的角度讨论,使用 y=wTx+b 对新样本分类时,用预测的 y 与一个阈值进行比较,y>0.5 即判别为正例,否则判别为负例.这里的 y 实际表达了正例的可能性(1-y是反例的可能性),0.5表明分类器认为正反例可能性相同.即 ,则预测为

机器不学习:如何处理数据中的「类别不平衡」?

机器不学习 jqbxx.com -机器学习好网站 机器学习中常常会遇到数据的类别不平衡(class imbalance),也叫数据偏斜(class skew).以常见的二分类问题为例,我们希望预测病人是否得了某种罕见疾病.但在历史数据中,阳性的比例可能很低(如百分之0.1).在这种情况下,学习出好的分类器是很难的,而且在这种情况下得到结论往往也是很具迷惑性的. 以上面提到的场景来说,如果我们的分类器总是预测一个人未患病,即预测为反例,那么我们依然有高达99.9%的预测准确率.然而这种结果是没有意

机器学习之类别不平衡问题 (3) —— 采样方法

机器学习之类别不平衡问题 (1) -- 各种评估指标 机器学习之类别不平衡问题 (2) -- ROC和PR曲线 机器学习之类别不平衡问题 (3) -- 采样方法 前两篇主要谈类别不平衡问题的评估方法,重心放在各类评估指标以及ROC和PR曲线上,只有在明确了这些后,我们才能据此选择具体的处理类别不平衡问题的方法.本篇介绍的采样方法是其中比较常用的方法,其主要目的是通过改变原有的不平衡样本集,以期获得一个平衡的样本分布,进而学习出合适的模型. 采样方法大致可分为过采样 (oversampling)

详解类别不平衡问题

本文详细介绍了类别不平衡问题,目录: 1 什么是类别不平衡问题? 2 类别不平衡导致分类困难的原因? 3 类别不平衡的解决方法? 4 如何选择类别不平衡中学习的评价指标? 5 关于解决方法选择的一些建议? 6 小结 1 什么是类别不平衡问题? 类别不平衡(class-imbalance),也叫数据倾斜,数据不平衡,就是指分类任务中不同类别的训练样例数目差别很大的情况.在现实的分类学习任务中,我们经常会遇到类别不平衡,例如交易欺诈.广告点击率预测.病毒脚本判断等:或者在通过拆分法解决多分类问题时,

Objective-C - 分类(类别)的应用 Category

分类(类别)的应用 Category /* 分类的作用:在不改变原来类内容的基础上,可以为类增加一些方法 使用注意: 1.分类只能增加方法,不能增加成员变量 2.分类方法实现中可以访问原来类中声明的成员变量 3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用 4.方法调用的优先级:分类(最后参与编译的分类优先) --> 原来类 --> 父类 */ #import "Person.h" #import "Person+One.h&

[Objective-c 基础 - 2.8] category分类/类别/类目

A.给某个类扩充方法(不改变原来的类) 例如,给类Person加上名为Simon的category,加上一个-study方法 使用()注明 Person+Simon.h 1 @interface Person (Simon) 2 - (void) study; 3 @end 4 5 Person+Simon.m 6 @implementation Person (Simon) 7 - (void) study 8 { 9 NSLog(@"学习----"); 10 } 11 @end 使

特征工程之特征表达

? ? ? ? ? 在特征工程之特征选择中,我们讲到了特征选择的一些要点.本篇我们继续讨论特征工程,不过会重点关注于特征表达部分,即如果对某一个特征的具体表现形式做处理.主要包括缺失值处理,特殊的特征处理比如时间和地理位置处理,离散特征的连续化和离散化处理,连续特征的离散化处理几个方面. 一.缺失值处理 ? ? ? ? ? 特征有缺失值是非常常见的,大部分机器学习模型在拟合前需要所有的特征都有值,不能是空或者NULL.那么如果有缺失值我们需要怎么处理呢? ? ?首先我们会看是该特征是连续值还是离

从重采样到数据合成:如何处理机器学习中的不平衡分类问题?

转载自[机器之心]http://www.jiqizhixin.com/article/2499本文作者为来自 KPMG 的数据分析顾问 Upasana Mukherjee 如果你研究过一点机器学习和数据科学,你肯定遇到过不平衡的类分布(imbalanced class distribution).这种情况是指:属于某一类别的观测样本的数量显著少于其它类别. 这个问题在异常检测是至关重要的的场景中很明显,例如电力盗窃.银行的欺诈交易.罕见疾病识别等.在这种情况下,利用传统机器学习算法开发出的预测模

分类问题中的数据不平衡问题

http://blog.csdn.net/heyongluoyao8/article/details/49408131 http://blog.csdn.net/lxg0807/article/details/71440477 ??在很多机器学习任务中,训练集中可能会存在某个或某些类别下的样本数远大于另一些类别下的样本数目.即类别不平衡,为了使得学习达到更好的效果,因此需要解决该类别不平衡问题. Jason Brownlee的回答: 原文标题:8 Tactics to Combat Imbala