• 正负样本比率失衡SMOTE


    正负样本比率失衡SMOTE

    背景

    这几天测试天池的优惠券预测数据在dnn上面会不会比集成树有较好的效果,但是正负样本差距太大,而处理这种情况的一般有欠抽样和过抽样,这里主要讲过抽样,过抽样有一种简单的方法叫随机过抽样,但是随机过抽样只是随机的复制,很容易过拟合,所以SMOTE比较好,SMOTE还有一些改进版本,更好用,这里讲一般的SMOTE即可

    公式

    (x) : 任意一个样本
    ( ilde{x}) : (x)最临近的(K)个样本的随机一个,(x ot= ilde{x})

    [x_{new}=x+rand(0,1) imes( ilde{x}-x) ]

    python实现

    import random
    from sklearn.neighbors import NearestNeighbors
    import numpy as np
    class Smote:
        def __init__(self,N=1,k=5):
            self.__shape=None
            self.__N=N
            self.__k=k
        
        def fit(self, samples):
            self.__shape=samples.shape #源样本的shape
            # 塑形为两位度才可以用KNN
            self.__samples=samples.reshape((self.__shape[0],-1)) 
            self.__tmp_shape=self.__samples.shape
            # 返回值的维度
            self.__ret_shape=(self.__shape[0]*self.__N,)+self.__shape[1:]
    
        def transform(self):
            # 如果没有喂给数据,则直接返回None
            if self.__shape == None:
                return None
            self.__index=0 # 清零新增数据的索引
            self.__X = np.zeros((self.__tmp_shape[0] * self.__N, self.__tmp_shape[1])) # 构造返回的数据,具体数据待填充
            neighbors=NearestNeighbors(n_neighbors=self.__k).fit(self.__samples)
            for i in range(self.__shape[0]): # 根据每一个样本产生一个新样本
                # nnarray当前样本最近k个的样本的索引
                nnarray=neighbors.kneighbors(self.__samples[i].reshape(1,-1),return_distance=False)[0]
                # 根据当前样本索引和,最近k和样本生成一个新样本
                self.__new_one_sample(i,nnarray)
            return self.__X.reshape(self.__ret_shape) # 重新塑形并返回
    
        def fit_transform(self, samples):
            self.fit(samples)
            return self.transform()
        
        # 根据当前样本索引和,最近k和样本生成一个新样本
        def __new_one_sample(self,i,nnarray):
            for _ in range(self.__N):
                #从K个最近的样本随机挑选不同于当前样本的一个样本
                nn_idx=random.choice(nnarray)
                while (nn_idx==i):
                    nn_idx=random.choice(nnarray)
                gap=self.__samples[nn_idx]-self.__samples[i]
                prob=random.random()
                # 根据公式生成新样本
                self.__X[self.__index]=self.__samples[i]+prob*gap
                self.__index+=1
    
    if __name__ == '__main__':
        a=np.array([[1,3,4],[2,5,6],[4,1,2],[5,1,4],[3,2,4],[5,3,5]])
        print("
    "*2, "测试维度为" , a.shape)
        print("*"*100)
        s=Smote()
        s.fit(a)
        print (s.transform())
        
        # 测试多维度支持
        b=np.zeros((10,)+a.shape)
        print("
    "*2, "测试维度为" , b.shape)
        print("*"*100)
        for i in range(10):
            b[i,:]=s.fit_transform(a)
        print (s.fit_transform(b))
    

    代码的使用方法

    假设你已经有label很少的数据 data (不包括label列)

    s=Smote()
    s.fit(data)
    s.transform()
    

    上面的实例是默认参数,可根据情况选择参数N和k
    数据扩增N被,从最近的k个样本选择一个样本参考(这里 参考 这个词可能不太准确,想不出其他词)来生成样本

    s=Smote(N=2, k=4)
    s.fit(data)
    s.transform()
  • 相关阅读:
    ubuntu 16.04 tmux
    ubuntu 16.04 samba 文件共享
    ubuntu 16.04 有道词典
    ubuntu bless 16字节每行
    Win7任务栏图标大小调整为等宽
    ubuntu 16.04 vnc server
    ubuntu 16.04 U盘多媒体不自动弹出
    Linux录屏软件
    通过apt-get安装nvidia驱动
    调试X Server
  • 原文地址:https://www.cnblogs.com/paiandlu/p/8081763.html
Copyright © 2020-2023  润新知