机器学习笔记:imblearn之SMOTE算法处理样本类别不平衡⼀、业务背景
⽇常⼯作、⽐赛的分类问题中常遇到类别型的因变量存在严重的偏倚,即类别之间的⽐例严重失调。
样本量差距过⼤会导致建模效果偏差。
例如逻辑回归不适合处理类别不平衡问题,会倾向于将样本判定为⼤多数类别,虽然能达到很⾼的准确率,但是很低的召回率。
出现样本不均衡场景主要有:
异常检测:恶意刷单、黄⽜、欺诈问题(欺诈⽤户样本可能少于1%);
客户流失:流失⽤户占⽐也⾮常低;
偶发事件:⽆法预判;
低频事件:频率很⼤,例如:双11/618等⼤促活动;
如果数据存在严重的不平衡,预测得出的结论往往也是有偏的,即分类结果会偏向于较多观测的类。
⼆、处理⽅法
针对此类问题,有⼏种处理办法。
1.正负样本惩罚权重
在算法实现过程中,对于分类不同样本数量的类别分别赋予不同的权重,再进⾏建模计算。
⼩样本量类别权重⾼,⼤样本权重低。
例如,XgBoost 算法提供参数 scale_pos_weight:
xgb.XGBClassifier(
learning_rate =0.1,
n_estimators=1000,
eval_metric=['logloss','auc','error'],
max_depth=5,
min_child_weight=1,
gamma=0,e6500
subsample=0.8,
colsample_bytree=0.8,
objective= 'binary:logistic',
nthread=4,
scale_pos_weight=883, # 负样本/正样本之⽐
华晨宝马铁西工厂ed=42)
2.组合、集成
每次⽣成训练集时,使⽤所有分类中的⼩样本量,⽽⼤样本量进⾏随机抽取,类似于随机森林的做法,进⾏ Bootstrap 采样。
3.抽样
最简单的上采样⽅法可以直接将少数类样本复制⼏份后添加到样本集中,最简单的下采样则可以直接只取⼀定百分⽐的多数类样本作为训练集。
⽋采样、下采样(under-sampling):删掉多的⼀类
from imblearn.under_sampling import RandomUnderSampler
过采样、上采样(over-sampling):通过Bootstrap抽样少的⼀类实现样本均衡
from imblearn.over_sampling import SMOTE
注意:使⽤ imblearn 时,数据中不能有缺失值,否则会报错!
⽋采样容易导致某些隐含信息丢失,过采样中有返回的抽样形成简单复制,容易产⽣模型过拟合。
三、SMOTE算法
1.⽬的
合成分类问题中的少数类样本,使得样本达到平衡。
2002 年 Chawla 提出 SMOTE 算法。
工作中
2.原理
合成的策略是对每个少数类样本A,从它的最近邻(KNN 欧⽒距离)中随机选取⼀个样本B,然后在A、B之间的连线上随机选取⼀点作为新合成的少数类样本(近似填充)。
采样最邻近算法,计算出每个少数类样本的K个近邻
从K个近邻中随机挑选N个样本进⾏随机线性插值
构造新的少数类样本
将新样本与原数据合成,产⽣新的训练集
四、imblearn包解释
1.安装
# 直接安装
pip install imblearn
pip install --ur imblearn
2.参数解释
imblearn.over_sampling.SMOTE(
论文文献综述怎么写radio='auto', # 旧版本
sampling_strategy="auto", # 新版本抽样⽐例
random_state=None, # 随机种⼦
k_neighbors=5, # 近邻个数
m_neighbors=10, # 随机抽取个数
out_step=0.5, # 使⽤kind='svm'
kind='regular', # ⽣成样本选项随机选取少数类的样本 'borderline1'、'borderline2'、'svm'
svm_estimator=None, # 指定SVM分类器
n_jobs=-1) # CPU数量并⾏
# kind解释
– borderline1:最近邻中的随机样本b与该少数类样本a来⾃于不同的类
– borderline2:随机样本b可以是属于任何⼀个类的样本
– svm:使⽤⽀持向量机分类器产⽣⽀持向量然后再⽣成新的少数类样本
五、实操
1.数据准备
#### 数据集⼀ ####
# 导⼊数据
import pandas as pd
df = pd.read_clipboard()
'''
a b c d e label
西瓜的英语0 5 3 4 9 7 0
兔子头饰图片1 3 8 9 4 10 0
2 6 8 8 8 7 1
3 5 7 1 5
4 0
4 5 5 5 8 6 0
5 4 1 2 7 3 0
6 6 6 6 10 2 1
7 6 9 6 7 6 0
8 3 1 5 5 2 0
9 8 4 5 2 6 1
传统的英文'''
# 数据分布
'''
a b c d e
label
0 7 7 7 7 7
1 3 3 3 3 3
'''
# 切⽚
x, y = df.iloc[:, :-1], df.iloc[:, -1]
# 同上
x, y = df.loc[:, df.columns != 'label'], df.loc[:, df.columns == 'label']
另外⼀种数据集准备⽅法。
# ⽣成类别不平衡数据
from sklearn.datats import make_classification
# 0和1⽐例为9:1
X, y = make_classification(n_class=2,
铁棍山药炖排骨class_p=2,
weights=[0.9,0.1],
n_informative=3,
n_redundant=1,
flip_y=0,
n_features=20,
n_clusters_per_class=1,
n_samples=1000,
random_state=10)
# 数据分布
from collections import Counter
Counter(y) # Counter({0: 900, 1: 100})
2.SMOTE过采样
imblearn 中过采样接⼝提供了随机过采样 RandomOverSampler、SMOTE、ADASYN 三种⽅式,调⽤⽅式基本⼀致。SMOTE 只适合处理连续性变量特征,不适合离散型特征。
# 导包
from imblearn.over_sampling import SMOTE
# 建模
smote_model = SMOTE(k_neighbors=2, random_state=42)
# fit
x_smote, y_smote = smote_model.fit_resample(x, y)
# 组合
df_smote = pd.concat([x_smote, y_smote], axis=1)
# 数据分布
upby('label').count()
'''
a b c d e
label
0 7 7 7 7 7
1 7 7 7 7 7
'''
fit_resample 与 fit_sample 因版本不同,修改⽅法名。
SMOTE 算法默认⽣成1:1的数据,如果想⽣成其他⽐例,可通过 ratio 参数设置。
# SMOTE
from imblearn.over_sampling import SMOTE
# 转换类型
X = X.astype('float64')
# SMOTE
smo = SMOTE(random_state=42)
X_smo, y_smo = smo.fit_resample(X, y)
# 查看分布
Counter(y_smo) # Counter({0: 900, 1: 900})
# 设置⽐例
# 旧版本
# smo = SMOTE(ratio={1:300}, random_state=42)
# 新版本
smo = SMOTE(sampling_strategy=1/3, random_state=42)
X_smo, y_smo = smo.fit_resample(X, y)
Counter(y_smo) # Counter({0: 900, 1: 300})
新版本通过 sampling_strategy 参数设置。否则会报错。
TypeError: __init__() got an unexpected keyword argument 'ratio'
3.RandomUnderSampler⽋采样
# 导包
from imblearn.under_sampling import RandomUnderSampler
# 建模
under_model = RandomUnderSampler()
# fit
x_under, y_under = under_model.fit_resample(x, y)
# 合并
df_under = pd.concat([x_under, y_under], axis=1)
# 数据分布
upby('label').count()
'''
a b c d e
label
0 3 3 3 3 3
1 3 3 3 3 3
'''
六、其他问题
ValueError: Unknown label type: ‘continuous’
标签类型必须是整型 int。
ValueError: Expected n_neighbors <= n_samples, but n_samples = 1, n_neighbors = 6数据量过少,导致⽆法求近邻样本。
可通过设置 k_neighbors 参数值,修改低⼀点数值。
参考链接:
参考链接:
参考链接:
参考链接:
参考链接:
参考链接:[
参考链接:
参考链接: