1. 程式人生 > >python資料預處理 :樣本分佈不均(過取樣和欠取樣)

python資料預處理 :樣本分佈不均(過取樣和欠取樣)

何為樣本分佈不均:

樣本分佈不均衡就是指樣本差異非常大,例如共1000條資料樣本的資料集中,其中佔有10條樣本分類,其特徵無論如何你和也無法實現完整特徵值的覆蓋,此時屬於嚴重的樣本分佈不均衡。

為何要解決樣本分佈不均:

樣本分部不均衡的資料集也是很常見的:比如惡意刷單、黃牛訂單、信用卡欺詐、電力竊電、裝置故障、大企業客戶流失等。
樣本不均衡將導致樣本量少的分類所包含的特徵過少,很難從中提取規律,即使得到分類模型,也容易產生過度依賴於有限的數量樣本而導致過擬合問題,當模型應用到新的資料上時,模型的準確性和健壯性將會很差。

樣本分佈不均的解決方法:

  • 過取樣 通過增加分類中樣本較少的類別的取樣數量來實現平衡,最直接的方法是簡單複製小樣本資料,缺點是如果特徵少,會導致過擬合的問題。經過改進的過抽樣方法通過在少數類中加入隨機噪聲、干擾資料或通過一定規則產生新的合成樣本。
  • 欠取樣 通過減少分類中多數類樣本的數量來實現樣本均衡,最直接的方法是隨機去掉一些多數類樣本來減小多數類的規模,缺點是會丟失多數類中的一些重要資訊。
  • 設定權重 對不同樣本數量的類別賦予不同的權重(通常會設定為與樣本量成反比)
  • 整合方法 每次生成訓練集時使用所有分類中的小樣本量,同時從分類中的大樣本量中隨機抽取資料來與小樣本量合併構成訓練集,這樣反覆多次會得到很多訓練集和訓練模型。最後在應用時,使用組合方法(例如投票、加權投票等)產生分類預測結果。這種方法類似於隨機森林。缺點是,比較吃計算資源,費時。

python程式碼:

# 生成不平衡分類資料集
from collections import
Counter from sklearn.datasets import make_classification X, y = make_classification(n_samples=3000, n_features=2, n_informative=2, n_redundant=0, n_repeated=0, n_classes=3, n_clusters_per_class=1, weights=[0.1, 0.05, 0.85], class_sep=
0.8, random_state=2018) Counter(y) # Counter({2: 2532, 1: 163, 0: 305}) # 使用RandomOverSampler從少數類的樣本中進行隨機取樣來增加新的樣本使各個分類均衡 from imblearn.over_sampling import RandomOverSampler ros = RandomOverSampler(random_state=0) X_resampled, y_resampled = ros.fit_sample(X, y) sorted(Counter(y_resampled).items()) # [(0, 2532), (1, 2532), (2, 2532)] # SMOTE: 對於少數類樣本a, 隨機選擇一個最近鄰的樣本b, 然後從a與b的連線上隨機選取一個點c作為新的少數類樣本 from imblearn.over_sampling import SMOTE X_resampled_smote, y_resampled_smote = SMOTE().fit_sample(X, y) sorted(Counter(y_resampled_smote).items()) # [(0, 2532), (1, 2532), (2, 2532)] # ADASYN: 關注的是在那些基於K最近鄰分類器被錯誤分類的原始樣本附近生成新的少數類樣本 from imblearn.over_sampling import ADASYN X_resampled_adasyn, y_resampled_adasyn = ADASYN().fit_sample(X, y) sorted(Counter(y_resampled_adasyn).items()) # [(0, 2522), (1, 2520), (2, 2532)] # RandomUnderSampler函式是一種快速並十分簡單的方式來平衡各個類別的資料: 隨機選取資料的子集. from imblearn.under_sampling import RandomUnderSampler rus = RandomUnderSampler(random_state=0) X_resampled, y_resampled = rus.fit_sample(X, y) sorted(Counter(y_resampled).items()) # [(0, 163), (1, 163), (2, 163)] # 在之前的SMOTE方法中, 當由邊界的樣本與其他樣本進行過取樣差值時, 很容易生成一些噪音資料. 因此, 在過取樣之後需要對樣本進行清洗. # 這樣TomekLink 與 EditedNearestNeighbours方法就能實現上述的要求. from imblearn.combine import SMOTEENN smote_enn = SMOTEENN(random_state=0) X_resampled, y_resampled = smote_enn.fit_sample(X, y) sorted(Counter(y_resampled).items()) # [(0, 2111), (1, 2099), (2, 1893)] from imblearn.combine import SMOTETomek smote_tomek = SMOTETomek(random_state=0) X_resampled, y_resampled = smote_tomek.fit_sample(X, y) sorted(Counter(y_resampled).items()) # [(0, 2412), (1, 2414), (2, 2396)] # 使用SVM的權重調節處理不均衡樣本 權重為balanced 意味著權重為各分類資料量的反比 from sklearn.svm import SVC svm_model = SVC(class_weight='balanced') svm_model.fit(X, y) # # EasyEnsemble 通過對原始的資料集進行隨機下采樣實現對資料集進行整合. # EasyEnsemble 有兩個很重要的引數: (i) n_subsets 控制的是子集的個數 and (ii) replacement 決定是有放回還是無放回的隨機取樣. from imblearn.ensemble import EasyEnsemble ee = EasyEnsemble(random_state=0, n_subsets=10) X_resampled, y_resampled = ee.fit_sample(X, y) sorted(Counter(y_resampled[0]).items()) # [(0, 163), (1, 163), (2, 163)] # BalanceCascade(級聯平衡)的方法通過使用分類器(estimator引數)來確保那些被錯分類的樣本在下一次進行子集選取的時候也能被取樣到. 同樣, n_max_subset 引數控制子集的個數, 以及可以通過設定bootstrap=True來使用bootstraping(自助法). from imblearn.ensemble import BalanceCascade from sklearn.linear_model import LogisticRegression bc = BalanceCascade(random_state=0, estimator=LogisticRegression(random_state=0), n_max_subset=4) X_resampled, y_resampled = bc.fit_sample(X, y) sorted(Counter(y_resampled[0]).items()) # [(0, 163), (1, 163), (2, 163)] # BalancedBaggingClassifier 允許在訓練每個基學習器之前對每個子集進行重抽樣. 簡而言之, 該方法結合了EasyEnsemble取樣器與分類器(如BaggingClassifier)的結果. from sklearn.tree import DecisionTreeClassifier from imblearn.ensemble import BalancedBaggingClassifier bbc = BalancedBaggingClassifier(base_estimator=DecisionTreeClassifier(), ratio='auto', replacement=False, random_state=0) bbc.fit(X, y)