SMOTE算法实现过程中应注意的一个问题

SMOTE是大家在机器学习任务中经常使用的处理非平衡数据的方法,其全称是Synthetic Minority Over-sampling Technique,论文的链接是:https://www.jair.org/index.php/jair/article/view/10302,其PDF版本的直接下载链接是:https://www.jair.org/index.php/jair/article/download/10302/24590。SMOTE的应用非常广泛,例如这篇文章:

Agrawal, Amritanshu, and Tim Menzies. "Is better data better than better data miners?: on the benefits of tuning SMOTE for defect prediction." Proceedings of the 40th International Conference on Software Engineering. ACM, 2018.

里统计,软件工程领域缺陷预测研究方向近些年的工作中有85%的论文使用SMOTE处理非平衡训练数据问题。不过我简单看了看大家实现SMOTE的代码,发现很多朋友都理解错了一个步骤,所以这里总结一下,也给相关朋友提个醒。

先看看SMOTE的伪代码:

其实这个伪代码写得很清楚了,但是我注意到大家出问题的主要是20到22行,在基于一个sample生成synthetic sample的时候,对于每一维特征,生成的gap都是重新计算的,而很多博客中写的方法,都是对所有特征统一生成一个gap(也就是对所有维度统一生成一个随机数),这样的确是误解了这个算法!

例如这些博客中写的:https://blog.csdn.net/panda_zjd/article/details/79200493https://blog.csdn.net/jiede1/article/details/70215477,话说,这种错误,实在是不应该啊!

我参考原论文和ICSE 2018这篇论文,以及这里:https://github.com/kaushalshetty/SMOTE/blob/master/smote.py,和这里:https://blog.csdn.net/jiede1/article/details/70215477 的代码,重新实现了一下smote代码,个人认为这是和原论文最接近的实现(同时加入了ICSE 2018论文中介绍的幂指数r)

# -*- coding:utf-8 -*-
'''
Created on 2018年9月21日

@author: Yu Qu
'''

import random
from sklearn.neighbors import NearestNeighbors
import numpy as np

class Smote(object):
    '''
    classdocs
    '''


    def __init__(self,samples,N=50,k=5,r=2):
        '''
        Constructor
        '''
        self.samples=samples
        self.T,self.numattrs=self.samples.shape
        self.N=N
        self.k=k
        self.r=r#这个r是计算Minkowski距离时的幂指数
        self.newindex=0
        
            
        
    def generate_synthetic_points(self):
        if(self.N<100):
            np.random.shuffle(self.samples)
            self.T=int(self.N*self.T/100)
            print self.T
            self.samples=self.samples[0:self.T,:]
            print self.samples
            self.N=100
        if(self.T<self.k):
            self.k=self.T-1
        
        N=int(self.N/100)
        self.synthetic = np.zeros((self.T * N, self.numattrs))       
        neighbors=NearestNeighbors(n_neighbors=self.k, algorithm='ball_tree', p=self.r).fit(self.samples)
        for i in range(len(self.samples)):
            nnarray=neighbors.kneighbors(self.samples[i].reshape((1,-1)),return_distance=False)[0]#Finds the K-neighbors of a point.
            self._populate(N,i,nnarray)
        return self.synthetic
    
    def _populate(self,N,i,nnarray):
        for j in range(N):
            attrs=[]
            nn=random.randint(0,self.k-1)
            for attr in range(self.numattrs):
                diff = self.samples[nnarray[nn]][attr] - self.samples[i][attr]
                gap = random.uniform(0,1)
                attrs.append(self.samples[i][attr] + gap*diff)
            self.synthetic[self.newindex]=attrs
            self.newindex+=1
            
a=np.array([[1,2,3],[4,5,6],[2,3,1],[2,1,2],[2,3,4],[2,3,4]])

smote=Smote(a,N=50)
synthetic_points=smote.generate_synthetic_points()
print synthetic_points

smote=Smote(a,N=100)
synthetic_points=smote.generate_synthetic_points()
print synthetic_points

 

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值