Python——样本类别不均衡问题+代码(基于imblearn包)

文章介绍了类别不平衡问题的概念,以及如何使用Python的imblearn库通过过采样(如SMOTE和ADASYN)和欠采样(如RandomUnderSampler和NearMiss)方法来解决这个问题。通过示例展示了如何调整数据集中的类别数量以达到更好的模型训练效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用Python的imblearn库解决类别不均衡问题

类别不平衡问题概述

类别不平衡问题是指采集的原始数据集中的不同类别数据样本数量相差过大,分布不均衡,如二分类下雨或不下雨问题中,与下雨相关的数据样本有50个,而与不下雨相关的数据样本有100个,在二分类过程中由于与下雨相关的数据样本过少,会导致学习到的与下雨相关的知识经验过少,进而错误地将下雨分类为不下雨。

解决类别不平衡问题常用的两种方法

解决类别不平衡问题的常用方法有两种:一是继续尽可能地收集到更多的数据样本使得类别均衡(个人认为在数据处理过程中不太现实),二是采用抽样方法,抽样方法又包括过采样和欠采样。

过采样

过采样是指通过增加类别数量少的数据样本数量使得数据样本均衡的方法,实现过采样的常用算法有SMOTE(Synthetic Minority Oversampling Technique)和ADASYN(Adaptive Synthetic) 。SMOTE算法的核心思想是合成类别数量少的数据样本,SMOTE算法会随机选取少数类样本来合成新样本,却不考虑周边样本的情况,进而容易导致新合成的样本有用特征信息过少及与多数类样本重叠的情况。ADASYN算法是根据数据分布的情况自适应地为不同少数类样本生成不同数量的新样本,不会像SMOTE算法一样为每个少数类样本合成相同数量的数据样本。过采样与欠采样相比,过采样使用的场景更多也更有效。

欠采样

欠采样是指通过减少类别数量多的数据样本数量使得数据样本均衡的方法,实现欠采样的常用算法有随机欠采样、原型生成和NearMiss,随机欠采样算法随机地选择目标类的数据子集来平衡数据,这种方法快速简便,原型生成算法要求原始数据集最好能够聚类成簇,减少数据集的样本数量,利余的数据样本足由原始数据集生成而并不直接来源于原始数输出据集。NearMiss算法利用了KNN算法思想,计算量会偏大。

Python中的imblearn库支持过采样和欠采样中及的算法,打开Anaconda Prompt应用程序或者windows命令菜单,在Anaconda Promp:应用程序或者windows的命令行窗口输入如下命令:

pip install imblearn

上述安装如果过慢,可采用第三方镜像:

清华:https://pypi.tuna.tsinghua.edu.cn/simple
阿里云:http://mirrors.aliyun.com/pypi/simple
中国科技大学 :https://pypi.mirrors.ustc.edu.cn/simple
华中理工大学:http://pypi.hustunique.com
山东理工大学:http://pypi.sdutlinux.org
例如:安装imblearn包:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple imblearn

判断样本类别分布

数据仍采用sns.heatmap变量相关热力图章节所用数据集

#标签类别分布
count=data['信用分类'].value_counts()
percent=count/count.sum()
print(percent,'\n',count)
#数据可视化
#count.plot(kind='line',color=['r'])
count.plot(kind='bar',fontsize=16,color=['g','r'])
plt.title('信用分类')#分类变量,1:好;0:差
plt.xticks(rotation=0)
for x,y in enumerate(count):
    plt.text(x,y+2,y,ha='center',fontsize=12)
plt.savefig("1.png")

1 0.69375
0 0.30625
Name: 信用分类, dtype: float64
1 555
0 245
Name: 信用分类, dtype: int64

在这里插入图片描述
可见样本存在类别不均衡问题。

过采样算法——imblearn.over_sampling

模板

########过采样############
from imblearn.over_sampling import SMOTE,ADASYN
from collections import Counter#快速统计样本类别
#X为数据样本特征,y为数据样本标签
result=sorted(Counter(y).items())
#result列表,列表每个元素为二元组,二元组含义为(类别,类别数量)
print("原始数据样本:")
for i in result:
    print(f"类别{i[0]}{i[1]}个数据样本")
#SMOTE
xSMOTE,ySMOTE=SMOTE().fit_resample(X,y)
result1=sorted(Counter(ySMOTE).items())
print("SMOTE算法处理后:")
for i in result1:
    print(f"类别{i[0]}{i[1]}个数据样本")
#ADASYN
xADASYN,yADASYN=ADASYN().fit_resample(X,y)
result2=sorted(Counter(YADASYN).items())
print("ADASYN算法处理后:")
for i in result2:
    print(f"类别{i[0]}{i[1]}个数据样本")

应用

from imblearn.over_sampling import SMOTE,ADASYN
from collections import Counter#快速统计样本类别
#加载数据
data=pd.read_csv(r'D:/Jupyter/data/training.csv',encoding="gb18030")#解决不是utf_8存储数据报错问题

data.drop(['编号'],axis=1,inplace=True)
x=data.drop(['信用分类'],axis=1)
y=data['信用分类']

xSMOTE,ySMOTE=SMOTE().fit_resample(x,y)
result1=sorted(Counter(ySMOTE).items())
print("SMOTE算法处理后:")
for i in result1:
    print(f"类别{i[0]}{i[1]}个数据样本")

xADASYN,yADASYN=ADASYN().fit_resample(x,y)
result2=sorted(Counter(yADASYN).items())
print("ADASYN算法处理后:")
for i in result2:
    print(f"类别{i[0]}{i[1]}个数据样本")

SMOTE算法处理后:
类别0有555个数据样本
类别1有555个数据样本
ADASYN算法处理后:
类别0有590个数据样本
类别1有555个数据样本

可见,ADASYN算法不会像SMOTE算法一样为每个少数类样本合成相同数量的数据样本。

欠采样算法——imblearn.under_sampling

########欠采样#############
from imblearn.under_sampling import RandomUnderSampler,ClusterCentroids,NearMiss
from collections import Counter#快速统计样本类别
#X为数据样本特征,y为数据样本标签
result=sorted(Counter(y).items())
#result列表,列表每个元素为二元组,二元组含义为(类别,类别数量)
print("原始数据样本:")
for i in result:
    print(f"类别{i[0]}{i[1]}个数据样本")
#RandomUnderSampler
xRandom,yRandom=RandomUnderSampler().fit_resample(X,y)
result1=sorted(Counter(yRandom).items())
print("随机欠采样算法处理后:")
for i in result1:
    print(f"类别{i[0]}{i[1]}个数据样本")
#ClusterCentroids
xCentroids,yCentroids=ClusterCentroids().fit_resample(X,y)
result2=sorted(Counter(YCentroids).items())
print("原型生成算法处理后:")
for i in result2:
    print(f"类别{i[0]}{i[1]}个数据样本")
#NearMiss
xCentroids,yCentroids=NearMiss().fit_resample(X,y)
result3=sorted(Counter(YCentroids).items())
print("NearMiss算法处理后:")
for i in result3:
    print(f"类别{i[0]}{i[1]}个数据样本")

PyCharm 批量更换变量名快捷键:Ctrl+R,很实用推荐!!!
应用

from imblearn.under_sampling import RandomUnderSampler,ClusterCentroids,NearMiss
from collections import Counter#快速统计样本类别

#加载数据
data=pd.read_csv(r'D:/Jupyter/data/training.csv',encoding="gb18030")#解决不是utf_8存储数据报错问题
data.drop(['编号'],axis=1,inplace=True)
X=data.drop(['信用分类'],axis=1)
y=data['信用分类']
#X为数据样本特征,y为数据样本标签
result=sorted(Counter(y).items())
#result列表,列表每个元素为二元组,二元组含义为(类别,类别数量)
print("原始数据样本:")
for i in result:
    print(f"类别{i[0]}{i[1]}个数据样本")
print()
#RandomUnderSampler
xRandom,yRandom=RandomUnderSampler().fit_resample(X,y)
result1=sorted(Counter(yRandom).items())
print("随机欠采样算法处理后:")
for i in result1:
    print(f"类别{i[0]}{i[1]}个数据样本")
print()
#ClusterCentroids
# xCentroids,yCentroids=ClusterCentroids().fit_resample(X,y)
# result2=sorted(Counter(yCentroids).items())
# print("原型生成算法处理后:")
# for i in result2:
#     print(f"类别{i[0]}有{i[1]}个数据样本")
#print()
#NearMiss
xCentroids,yCentroids=NearMiss().fit_resample(X,y)
result3=sorted(Counter(yCentroids).items())
print("NearMiss算法处理后:")
for i in result3:
    print(f"类别{i[0]}{i[1]}个数据样本")
print()

原始数据样本:
类别0有245个数据样本
类别1有555个数据样本
随机欠采样算法处理后:
类别0有245个数据样本
类别1有245个数据样本
NearMiss算法处理后:
类别0有245个数据样本
类别1有245个数据样本

注:运行原型生成算法代码会报错:AttributeError: ‘NoneType’ object has no attribute ‘split’.
目前未解决,如果有解决方法的可以私信或者评论区告诉我,好多算法代码运行都会遇到这个错误,我真的会谢。

想要了解更多Python采样方法,在这里推荐一篇博客:python抽样方法详解及实现

### 解决正负样本平衡的方法 在面对机器学习中的正负样本平衡问题时,可以采用多种采样策略来改善模型性能。这些方法旨在调整训练集内的类别分布,从而使得少数类能够被更好地识别。 #### 过采样 (Oversampling) 过采样的核心理念是在保持多数类变的情况下增加少数类的数量。这可以通过简单复制现有实例或者生成新的合成实例实现。例如,在某些情况下,经过过采样之后的新数据集中总观测数达到了1380条记录[^2]。这种方法有助于防止模型偏向于预测占大多数的类别,并给予较少见事件更多关注的机会。 #### 欠采样 (Undersampling) 欠采样则是减少多数类的数据量至与少数类相匹配的程度。虽然这种方式可能会丢失一些有用的信息,但它能有效降低计算成本并简化建模过程。重要的是要确保所选留下的样本具有代表性,以便维持原始数据的整体特征。 #### 组合方法 (Combination Methods) 除了单独应用上述两种技术外,还可以考虑组合使用它们——即先对多数类执行随机或启发式的欠采样,再针对剩余部分实施适当形式的过采样操作。这种混合方式往往能在保留更多信息的同时达到更好的平衡效果。 #### 合成少数类过采样技术(SMOTE, Synthetic Minority Over-sampling Technique) SMOTE是一种特别流行的算法,它是单纯地重复已有案例而是创建介于两个相近邻居之间的新点作为额外训练材料的一部分。此法仅增加了多样性而且减少了因直接复制带来的风险。 ```python from imblearn.over_sampling import SMOTE smote = SMOTE() X_resampled, y_resampled = smote.fit_resample(X_train, y_train) ``` 当发现数据存在严重的类别失衡状况时确实令人沮丧,因为之前看似优异的结果可能只是表面现象而非真实表现[^3]。为了应对这种情况,建议尝试以上提到的同类型的重采样方案,并结合其他改进措施如优化评估标准等共同作用以提升最终成果的质量。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值