这篇博客主要是关于训练样本中出现的类不均衡问题的一些解决方法。
这是一篇自主学习的博客,收集了很多关于这方面的好的资料。
1.About
Somte:Synthetic Minority Oversampling Technique 中文:合成少数类过采样技术。传统方案——随机过采样。缺点:随机过采样采取简单复制样本的策略来增加少数类样本,这样容易产生模型过拟合的问题,即使得模型学习到的信息过于特别(Specific)而不够泛化(General),SMOTE算法是基于随机过采样算法的一种改进方案,基本思想是对少数类样本进行分析并根据少数类样本人工合成新样本添加到数据集中。
参考博客 https://blog.csdn.net/jiede1/article/details/70215477点击打开链接
#SMOTE算法及其python实现
import random
from sklearn.neighbors import NearestNeighbors
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
#定义Smote类,类一般首字母大写,其声明和定义同时进行。
class Smote:
def __init__(self,samples,N=10,k=5):
#行数 列数
self.n_samples,self.n_attrs=samples.shape
self.N=N #采样点数
self.k=k #k近邻
self.samples=samples #样本
self.newindex=0
def over_sampling(self):
N=int(self.N/100)
#存储生成的样本,共6*10个,所以构建一个60行,3列的数组synthetic
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)):
#第i个点
print('第',i,'个',end='')
print('samples',self.samples[i])
print(self.samples[i].reshape(1,-1))
#kneighbors返回值第一个是最短距离,第二个是索引
nnarray=neighbors.kneighbors(self.samples[i].reshape((1,-1)),return_distance=False)[0]
#Finds the K-neighbors of a point.
print ('与上述点距离最近的五个点索引值分别为:',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): #0-9 不包括10,10个数据
nn=random.randint(0,self.k-1) #包括end,随机生成0-4之间的整数值,包括0和4
#随机从k近邻中选择若干样本
dif=self.samples[nnarray[nn]]-self.samples[i]
#返回随机生成的一个实数,它在[0,1)范围内
gap=random.random()
# 生成随机数据
self.synthetic[self.newindex]=self.samples[i]+gap*dif
self.newindex+=1
def show(a,b):
x = np.array(a[:, 0])
y = np.array(a[:, 1])
z = np.array(a[:, 2])
ax = plt.subplot(211, projection='3d') # 创建一个三维的绘图工程
ax.scatter(x, y, z, c='g')
ax.set_zlabel('Z') # 坐标轴
ax.set_ylabel('Y')
ax.set_xlabel('X')
x = np.array(b[:, 0])
y = np.array(b[:, 1])
z = np.array(b[:, 2])
ax = plt.subplot(212, projection='3d') # 创建一个三维的绘图工程
ax.scatter(x, y, z, c='y')
ax.set_zlabel('Z') # 坐标轴
ax.set_ylabel('Y')
ax.set_xlabel('X')
plt.show()
if __name__ == '__main__':
a=np.array([[1,2,3],[4,5,6],[2,3,1],[2,1,2],[2,3,4],[2,3,4]])#原始数据集
s=Smote(a,N=1000)
s.over_sampling()
b = s.synthetic #生成的数据集
show(a,b)
这是参考上述博客地址写得smote代码,加了很多注释,非常适合初学者看,读者可以直接复制粘贴运行。其中比较难的NearestNeighbors和kneighbors函数请参考sklearn文档。链接如下:点击打开链接
上面有非常详细的参数说明。感谢上述博主的代码,对我的学习很有帮助。
评价:该算法主要存在两方面的问题。一是在近邻选择时,存在一定的盲目性。从上面的算法流程可以看出,在算法执行过程中,需要确定K值,即选择多少个近邻样本,这需要用户自行解决。从K值的定义可以看出,K值的下限是M值(M值为从K个近邻中随机挑选出的近邻样本的个数,且有M< K),M的大小可以根据负类样本数量、正类样本数量和数据集最后需要达到的平衡率决定。但K值的上限没有办法确定,只能根据具体的数据集去反复测试。因此如何确定K值,才能使算法达到最优这是未知的。
另外,该算法无法克服非平衡数据集的数据分布问题,容易产生分布边缘化问题。由于负类样本的分布决定了其可选择的近邻,如果一个负类样本处在负类样本集的分布边缘,则由此负类样本和相邻样本产生的“人造”样本也会处在这个边缘,且会越来越边缘化,从而模糊了正类样本和负类样本的边界,而且使边界变得越来越模糊。这种边界模糊性,虽然使数据集的平衡性得到了改善,但加大了分类算法进行分类的难度.
(时间2018.6.13)
2.对此,提出了改进的smote算法,Borderline-smote和Adasyn
参考博客地址:https://blog.csdn.net/u011414200/article/details/50664266 点击打开链接
在 Borderline-SMOTE 算法 中,只有最近邻样本集中多数类对于少数类的那些 xi
才会被选中形成 “危险集 (DANGER)”。因此,DANGER 集中的样本代表少数类样本的边界(最容易被错分的样本)。然后对 DANGER 集使用 SMOTE 算法来在边界附近产生人工合成少数类样本。
SMOTE 和 Borderline-SMOTE 算法最大的不同就是:SMOTE 算法为每一个少数类样本生成合成样本,然而 Borderline-SMOTE 算法只为那些 “靠近” 边界的少数类样本生成合成样本。
For each point p in S:
1. Compute its m nearest neighbors in T. Call this set Mp and let m'= |Mp ∩ L|.
2. If m'= m, p is a noisy example. Ignore p and continue to the next point.
3. If 0 ≤ m'≤m/2, p is safe. Ignore p and continue to the next point.
4. If m/2 ≤ m'≤ m, add p to the set DANGER.
For each point d in DANGER, apply the SMOTE algorithm to generate synthetic examples.
其他有somte相关的优化:SMOTEBOOST,AND-SMOTE,C_smote,SMOTE-DGC,SMOTE-D,SAFE-LEVEL-SMOTE,Random-SMOTE,
点击打开链接
3.数据清洗
移除重复的样本,可以在训练集中建立良号定义的类簇,这反过来又可以为提高分类性能定义良好的分类准则。在这个领域中,典型的方法包括 OSS 方法、简明近邻规则、Tomek线(CNN+Tomek)集成方法、基于编辑近邻(ENN)的近邻 清理规则(NCL)、SMOTE 和ENN 的集成(SMOTE+ENN)以及 SMOTE 与 Tomek 线的集成(SMOTE+Tomek)。
点击打开链接