1. 程式人生 > >機器學習:樣本比例失衡的處理

機器學習:樣本比例失衡的處理

最近在做個專案,樣本比例嚴重失衡,正負樣本比例差不多1:10的樣子。如此嚴重失衡的樣本比例,模型訓練的效果自然不會好,甚至很差。還是那句話,資料決定了上限,模型只是逼近這個上限而已。
那遇到這種情況我們改如何解決呢?方法如下:

  1. 增加缺失樣本
    這是最好也是最難的方法,因為一般樣本比例嚴重失衡肯定是有原因的。比如預測信用卡逾期,逾期的人肯定是極少數,所以很難蒐集更多的逾期樣本。

  2. 過取樣
    複製樣本量少的資料,加入樣本中,以達到正負樣本儘量的平衡。經過測試該方法簡單易用。

  3. 欠取樣
    刪除部分資料佔比高的樣本資料,從而達到平衡效果。經過測試,這個方法未必有過取樣好用,不知道是不是我的資料有問題。

  4. SMOTE
    SMOTE(Synthetic Minority Oversampling Technique)屬於過取樣的一種。它的基本思想是對少數類樣本進行分析並根據少數類樣本人工合成新樣本新增到資料集中,從而提升模型效果。下面會貼出SMOTE的實現方法。

  5. 採用適合的演算法
    對於樣本比例嚴重失衡的情況,傳統的分類演算法,比如LR等,很難有好的表現,所以我們要考慮換種演算法。GBDT,XGBOOST等對於這類樣本就有很好的表現,非常適合處理這樣的資料。

  6. 多分類
    當你的樣本為二分類,且樣本比例嚴重失衡時,可以考慮將樣本分為多類,這樣可能有意想不到的收穫。

最後貼下Python實現SMOTE演算法的程式碼:

#SMOTE演算法及其python實現
import random
from sklearn.neighbors import NearestNeighbors
import numpy as np
import pandas as pd

class Smote:
    def __init__(self,samples,N=10,k=5):
        self.n_samples,self.n_attrs=samples.shape
        self.N=N
        self.k=k
        self.samples=samples
        self.newindex=0
       # self.synthetic=np.zeros((self.n_samples*N,self.n_attrs))

    def over_sampling(self):
        N=int(self.N/100)
        self.synthetic = np.zeros((self.n_samples * N, self.n_attrs))
        neighbors=NearestNeighbors(n_neighbors=self.k).fit(self.samples)
        print ('neighbors',neighbors)
        for i in range(len(self.samples)):
            print('samples',self.samples[i])
            nnarray=neighbors.kneighbors(self.samples[i].reshape((1,-1)),return_distance=False)[0]  #Finds the K-neighbors of a point.
            print ('nna',nnarray)
            self._populate(N,i,nnarray)
        return self.synthetic


    # for each minority class sample i ,choose N of the k nearest neighbors and generate N synthetic samples.
    def _populate(self,N,i,nnarray):
        for j in range(N):
            print('j',j)
            nn=random.randint(0,self.k-1)  #包括end
            dif=self.samples[nnarray[nn]]-self.samples[i]
            gap=random.random()
            self.synthetic[self.newindex]=self.samples[i]+gap*dif
            self.newindex+=1
            print(self.newindex)


df = pd.read_csv('/data.csv')
s=Smote(df.values,N=600)
result = s.over_sampling()
df_smote = pd.DataFrame(result)
df_smote.to_csv('/data_processed.csv',index=False,encoding='utf_8_sig')

參考資料:
https://blog.csdn.net/jiede1/article/details/70215477