机器学习:样本比例失衡的处理

最近在做个项目,样本比例严重失衡,正负样本比例差不多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

猜你喜欢

转载自blog.csdn.net/opp003/article/details/84580207