模型的准确率是0.75,ROC分数

非平衡数据会影响最后的评判效果,严重的会带来过拟合的效果,即模型总是把样本划分到样本量较多的那一种。为了让模型的评判更准确,我们需要对非平衡数据进行一定的处理,主要有以下几种方式:

  • 欠采样
  • 过采样
  • 人工合成
  • 调权重

在开始介绍不同的处理方式之前,我们先引入一组非平衡数据。

 
  1. #导入一些相关库

  2. from sklearn.model_selection import train_test_split

  3. from sklearn.linear_model import LogisticRegression

  4. from sklearn.metrics import classification_report

  5. from sklearn.metrics import roc_curve, auc

  6. from sklearn.preprocessing import scale

  7. #导入数据

  8. df=pd.read_excel(r"C:\Users\zhangjunhong\Desktop\Unbanlanced-data.xlsx").fillna(0)

  • 1

看一下正负样本的具体数据量情况。

 
  1. x=df.iloc[:,1:-1]

  2. y=df["label"]

  3. print(y.value_counts())

  4. print("-------------------------")

  5. print(y.value_counts(normalize=True))

  • 1

该数据量的正负样本比例接近7:3,我们看一下不做任何处理的情况下,模型的预测效果如何。

 
  1. #将模型进行封装,方便调用

  2. def get_result_data(x,y):

  3. x_=scale(x,with_mean=True,with_std=True)

  4. x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.4,random_state=0)

  5. model=LogisticRegression()

  6. clf=model.fit(x_train,y_train)

  7. print("LR模型测试成绩:{:.2f}".format(clf.score(x_test,y_test)))

  8. y_pred=clf.predict(x_test)

  9. target_names = ['class 0', 'class 1']

  10. print(classification_report(y_test, y_pred, target_names=target_names))

  11. y_pred1=clf.decision_function(x_test)

  12. fpr,tpr,threshold=roc_curve(y_test,y_pred1)

  13. rocauc=auc(fpr,tpr)#计算AUC

  14. print("ROC分数:{:.2f}".format(rocauc))

  15.  
  16. if __name__=="__main__":

  17. get_result_data(x,y)

  • 1

模型的准确率是0.75,ROC分数也就是AUC值为0.76,看着还不错,但是class1的召回率要明显高于class0的召回率,这是因为原样本量中,class1的量要明显高于class0的原因。

欠采样

下采样(under-sampling),是对非平衡数据中样本数较多的那一类进行采样,采样使其约等于样本量较少那一类的样本量。

 
  1. df1=df[df["label"]==1]#正样本部分

  2. df0=df[df["label"]==0]#负样本部分

  3.  
  4. #对正样本按0.5的比例进行下采样

  5. df2=df1.sample(frac=0.5)

  6.  
  7. #将下采样后的正样本与负样本进行组合

  8. df_new=pd.concat([df0,df2])

  9.  
  10. x=df_new.iloc[:,1:-1]

  11. y=df_new["label"]

  12.  
  13. #下采样以后正负样本量情况

  14. print(y.value_counts())

  15. print("-------------------------")

  16. print(y.value_counts(normalize=True))

  • 1

对模型进行下采样以后,正负样本的样本量基本接近1:1,符合我们目的,接下来看看下采样后的模型表现。

 
  1. if __name__=="__main__":

  2. get_result_data(x,y)

  • 1

模型的准确率略有下降,但是ROC分数没发生什么变化,class0和class1的召回率也接近相等。

过采样

过采样(over-sampling),是对非平衡数据中样本数较少的那一类进行采样,常规的做法就是将其复制几遍来达到正负样本平衡,因为是同样的数据复制多份,很容易发生过拟合,一般比较少用。具体的实现方式就比较简单啦,这里不罗列。

人工合成

https://www.douban.com/photos/photo/2530291642/
https://www.douban.com/photos/photo/2530291912/
https://www.douban.com/photos/album/1674186927/
https://www.douban.com/photos/photo/2530292424/
https://www.douban.com/photos/photo/2530292452/
https://www.douban.com/photos/photo/2530292483/
https://www.douban.com/photos/photo/2530292535/

人工合成就是人为地去合成一些样本量较少的数据,来达到正负样本平衡,人工合成数据能够很好地避免过采样带来的模型过拟合。比较常用的方法就是SMOTE。

SMOTE的算法原理如下:

  1.  
  2. from imblearn.over_sampling import SMOTE

  3. print('Original dataset shape {}'.format(Counter(y)))

  4. sm = SMOTE(random_state=42)

  5. X_res, y_res = sm.fit_sample(x, y)

  6. print('Resampled dataset shape {}'.format(Counter(y_res)))

  • 1

原本正负样本绝对量分别为12193:5617,人工合成部分样本量以后,正负样本的绝对量变为了12193:12193,完全平衡。

人工合成以后模型预测效果

 
  1. if __name__=="__main__":

  2. get_result_data(X_res, y_res)

  • 1

模型的准确率和ROC分数较欠采样都有略微的上涨,其中class0的召回上涨,class1略降。

调权重

调权重就是调整模型中正负样本的在模型表现中的表决权重,以此来平衡样本绝对量的不平衡。比如正负样本绝对量的比值为1:10,为了抵消这种量级上的不平衡,我们在模型中可以给与模型正负样本10:1的表决权重,也就是10个正样本的表决相当于1个负样本的表决。

这个过程我们也可以直接设置模型参数class_weight="balanced"进行实现。

 
  1. x_=scale(x,with_mean=True,with_std=True)

  2. x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.4,random_state=0)

  3.  
  4. model=LogisticRegression(class_weight="balanced")

  5. clf=model.fit(x_train,y_train)

  6. print("LR模型测试成绩:{:.2f}".format(clf.score(x_test,y_test)))

  7. y_pred=clf.predict(x_test)

  8.  
  9. target_names = ['class 0', 'class 1']

  10. print(classification_report(y_test, y_pred, target_names=target_names))

  11.  
  12. y_pred1=clf.decision_function(x_test)

  13. fpr,tpr,threshold=roc_curve(y_test,y_pred1)

  14. rocauc=auc(fpr,tpr)#计算AUC

  15. print("ROC分数:{:.2f}".format(rocauc))

  • 1

调权重的结果和人工合成数据的结果接近一致。

最后

https://www.douban.com/photos/photo/2530291642/
https://www.douban.com/photos/photo/2530291912/
https://www.douban.com/photos/album/1674186927/
https://www.douban.com/photos/photo/2530292424/
https://www.douban.com/photos/photo/2530292452/
https://www.douban.com/photos/photo/2530292483/
https://www.douban.com/photos/photo/2530292535/

通过上面几种方法的模型结果可以看出:

  • 用任意一种方式处理或者不处理,ROC基本是一致的,这也验证了我们在前面的推文中说到的,ROC是和样本是否平衡没关系的。
  • 如果不做任何处理,模型的准确率会高,但是会发生严重的过拟合。
  • 在做处理的这几种方式中,欠采样的效果要差于其他三种。
  • 综合来看,直接在模型参数中调权重是效果最好,也是最快捷的一种方式,不用事先去做什么处理。

本文最后的结论是针对本次数据得出的结论,不代表在任何数据上效果都是如此,可能会限于数据本身的原因,结果会有所不同,本文重点讲述非平衡数据不同的处理方式以及实现方式

猜你喜欢

转载自blog.csdn.net/qq_38459897/article/details/81480052