首頁>技術>

1. 什麼是資料不平衡

所謂的資料不平衡(imbalanced data)是指資料集中各個類別的數量分佈不均衡;不平衡資料在現實任務中十分的常見。如

信用卡欺詐資料:99%都是正常的資料, 1%是欺詐資料貸款逾期資料

不平衡資料一般是由於資料產生的原因導致的,類別少的樣本通常是發生的頻率低,需要很長的週期進行採集。

在機器學習任務(如分類問題)中,不平衡資料會導致訓練的模型預測的結果會偏向於樣本數量多的類別,這個時候除了要選擇合適的評估指標外,想要提升模型的效能,就要對資料和模型做一些預處理。

處理資料不平衡的主要方法:

欠取樣過取樣綜合取樣模型整合調整類別權重或者樣本權重2. 資料不平衡處理方法

imbalanced-learn庫提供了許多不平衡資料處理的方法,本文的例子都以imbalanced-learn庫來實現。

pip install -U imbalanced-learn  

https://github.com/scikit-learn-contrib/imbalanced-learn

本文例子的資料來自進行中的比賽山東省第二屆資料應用創新創業大賽-日照分賽場-公積金貸款逾期預測

先來看下資料

import pandas as pd  train_data = './data/train.csv'  test_data = './data/test.csv'  train_df = pd.read_csv(train_data)  test_df = pd.read_csv(test_data)  print(train_df.groupby(['label']).size())  # label為是否違約, 1為違約, 0為非違約  #     label  # 0    37243  # 1     2757 
2.1 欠取樣

所謂欠取樣,就是將數量多類別(記為majority)的樣本進行抽樣,使之數量與數量少的類別(minority)的數量相當,以此達到數量的平衡。

由於欠取樣是丟失了一部分資料,不可避免的使得數量多類別樣本的分佈發生了變化(方差變大)。好的欠取樣策略應該儘可能保持原有資料分佈。

一種是overlapping的資料,就是多餘的資料一種是干擾的資料,干擾minority的分佈

基於此,有兩種思路來欠取樣

from imblearn.under_sampling import TomekLinks  X_train = train_df.drop(['id', 'type'], axis=1)  y = train_df['label']  tl = TomekLinks()  X_us, y_us = tl.fit_sample(X_train, y)  print(X_us.groupby(['label']).size())  # label  # 0    36069  # 1     2757 

從上可知, 有1174個tomek-link被刪除,好像刪除還不夠多,可以測試下是否對分類結果有幫助。需要注意的因為需要計算最近鄰,所以樣本屬性必須數值屬性,或者可以轉化為數值屬性。

聚類

這類方法透過多個聚類,把原始樣本劃分成多個聚類簇,然後用每個聚類簇的中心來代替這個聚類簇的特性,完成取樣的目的。可知,這種取樣的樣本不是來自原始樣本集,而是聚類生成 的。

from imblearn.under_sampling import ClusterCentroids       cc = ClusterCentroids(random_state=42)      X_res, y_res = cc.fit_resample(X_train, y)      X_res.groupby(['label']).size()      # label      # 0    2757      # 1    2757 

im-balance提供的欠取樣的方法如下:

Random majority under-sampling with replacementExtraction of majority-minority Tomek linksUnder-sampling with Cluster CentroidsNearMiss-(1 & 2 & 3)Condensed Nearest NeighbourOne-Sided SelectionNeighboorhood Cleaning RuleEdited Nearest NeighboursInstance Hardness ThresholdRepeated Edited Nearest NeighboursAllKNN2.2 過取樣

所謂過取樣,就是將數量少的類別(minority)的樣本進行copy,使之數量與數量多的類別(majortity)的數量相當,以此達到數量的平衡。由於複製了多份minoruty樣本,過取樣會改變minority方差。

過取樣一種簡單的方式是隨機copy minority的樣本;另外一種是根據現有樣本生成人造樣本。這裡介紹人造樣本的經典演算法SMOTE(Synthetic Minority Over-sampling Technique)。

SMOTE基於minority樣本相似的特徵空間構造新的人工樣本。步驟如下:

選擇一個minority樣本,計算其KNN鄰居在K個鄰居中,隨機選擇一個近鄰修改某一個特徵,偏移一定的大小:偏移的大小為該minority樣本與該近鄰差距乘以一個小的隨機比率(0, 1), 就此生成新樣本
from imblearn.over_sampling import SMOTE  smote = SMOTE(k_neighbors=5, random_state=42)  X_res, y_res = smote.fit_resample(X_train, y)  X_res.groupby(['label']).size()  # label  # 0    37243  # 1    37243 

對於SMOTE方法,對每一個minority都會構造新樣本。但是並不總是這樣的,考慮下面A,B,C三個點。從資料分佈來看,C點很可能是一個異常點(Noise),B點是正常分佈的點(SAFE),而A點分佈在邊界位置(DANGER);直觀上,對於C點我們不應該去構造新樣本,對B點,構造新樣本不會豐富minority類別的分佈。只有A點,如果構造新樣本能夠使得A點從(DANGER)到(SAFE),加強minority類別的分類邊界。這個就是Borderline-SMOTE

from imblearn.over_sampling import BorderlineSMOTE  bsmote = BorderlineSMOTE(k_neighbors=5, random_state=42)  X_res, y_res = bsmote.fit_resample(X_train, y)  X_res.groupby(['label']).size()  # label  # 0    37243  # 1    37243 

ADASYN方法從保持樣本分佈的角度來確定生成資料,生成資料的方式和SMOTE是一樣的,不同在於每個minortiy樣本生成樣本的數量不同。

先確定要生成樣本的數量 beta為[0, 1]對每個每個minortiy樣本,確定有它生成樣本的比例。先找出K最近鄰,計算K最近鄰中屬於majority的樣本比例(即分子),Z是歸一化因子,保證所有的minortiry的比例和為1,可以認為是所有分子的和。計算每個minortiy生成新樣本的數量按照SMOTE方式生成樣本
from imblearn.over_sampling import ADASYN   adasyn = ADASYN(n_neighbors=5, random_state=42)  X_res, y_res = adasyn.fit_resample(X_train, y)  X_res.groupby(['label']).size()  # label  # 0    37243  # 1    36690 

im-balance提供的過取樣的方法如下(包括SMOTE演算法的變種):

Random minority over-sampling with replacementSMOTE - Synthetic Minority Over-sampling TechniqueSMOTENC - SMOTE for Nominal ContinuousbSMOTE(1 & 2) - Borderline SMOTE of types 1 and 2SVM SMOTE - Support Vectors SMOTEADASYN - Adaptive synthetic sampling approach for imbalanced learningKMeans-SMOTEROSE - Random OverSampling Examples2.3 綜合取樣

過取樣是針對minority樣本,欠取樣是針對majority樣本;而綜合取樣是既對minority樣本,又對majority樣本,同時進行操作的方法。主要有SMOTE+Tomek-links和SMOTE+Edited Nearest Neighbours。

綜合取樣的方法,是先進行過取樣,在進行欠取樣。

from imblearn.combine import SMOTETomek  smote_tomek = SMOTETomek(random_state=0)  X_res, y_res = smote_tomek.fit_sample(X_train, y)  X_res.groupby(['label']).size()  # label  # 0    36260  # 1    36260 
2.4 模型整合

這裡的模型整合主要體現在資料上,即用眾多平衡的資料集(majortiry的樣本進行欠取樣加上minority樣本)訓練多個模型,然後進行整合。imblearn.ensemble提供幾種常見的模型整合演算法,如BalancedRandomForestClassifier

from imblearn.ensemble import BalancedRandomForestClassifier  from sklearn.datasets import make_classification  X, y = make_classification(n_samples=1000, n_classes=3,                             n_informative=4, weights=[0.2, 0.3, 0.5],                             random_state=0)  clf = BalancedRandomForestClassifier(max_depth=2, random_state=0)  clf.fit(X, y)    print(clf.feature_importances_)    print(clf.predict([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                      0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])) 

im-balance提供的模型整合的方法如下

Easy Ensemble classifierBalanced Random ForestBalanced BaggingRUSBoost2.5 調整類別權重或者樣本權重

對於很多用梯度下降方法來學習(使得某個損失Loss最小)的機器學習的方法,可以透過調整類別權重或樣本權重的方式,來一定程度上平衡不平衡資料。如gbdt模型lightgbm 中 class_weight

import lightgbm as lgb  clf = lgb.LGBMRegressor(num_leaves=31,                           min_child_samples= np.random.randint(20,25),                          max_depth=25,                          learning_rate=0.1,                           class_weight={0:1, 1:10},                          n_estimators=500,                           n_jobs=30) 
3. 總結

本文分享了常見的幾種處理不平衡資料集的方法,並且提供imbalanced-learn的簡單例子。總結如下:

欠取樣: 減少majoritry樣本過取樣:增加minority樣本綜合取樣:先過取樣,在欠取樣模型整合:製造平衡資料(majoritry樣本欠取樣+minority樣本),多次不同的欠取樣,訓練不同的模型,然後融合不管是欠取樣和過取樣,都一定程度的改變了原始資料的分佈,可能造成模型過擬合。需要去嘗試哪種方法,符合實際的資料分佈。當然不一定有效果,去勇敢嘗試吧 just do it!近期有很多朋友透過私信諮詢有關Python學習問題。為便於交流,點選藍色自己加入討論解答資源基地

142
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • MicroPython藍芽BLE例程實操(三)