樣本不均衡數(shù)據(jù)處理

當(dāng)我們?cè)谧鰴C(jī)器學(xué)習(xí)任務(wù)時(shí),會(huì)經(jīng)常遇到這樣的數(shù)據(jù)集,兩種樣本的數(shù)量相差特別懸殊。這就會(huì)導(dǎo)致一個(gè)問題,在建模的時(shí)候,模型會(huì)特別注重?cái)?shù)量多的樣本,而忽視數(shù)量少的樣本,覺得數(shù)量少的樣本不夠重要。生活中也有許多這樣的例子,如在一份患者數(shù)據(jù)集當(dāng)中,絕大多數(shù)患者都是正常的,只有極少數(shù)患者會(huì)得癌癥。在一份銀行貸款數(shù)據(jù)集中,絕大數(shù)用戶都能按時(shí)還款,只有極少數(shù)用戶會(huì)欠款不還。如果我們我們的模型只關(guān)注正常樣本,而忽視了這些極少數(shù)的異常樣本,那么這樣的模型是沒有什么實(shí)際價(jià)值的。


bank.jpg

銀行貸款是一件犯錯(cuò)成本很高的事情,我們需要根據(jù)用戶所提交的資料來判斷是否給該用戶貸款以及貸款的金額。如果一個(gè)用戶能夠正常還款,而我們沒有給他貸款,我們損失的最多是貸款產(chǎn)生的利息;如果一個(gè)用戶無法償還貸款,而我們貸給他一大筆錢,那我們損失的將是整個(gè)本金。所以對(duì)于該情況下的模型而言,必須能夠準(zhǔn)確識(shí)別出這些極少數(shù)的異常樣本。

對(duì)于機(jī)器學(xué)習(xí)模型而言,重視多數(shù)樣本,忽視少數(shù)樣本,這是符合機(jī)器甚至是人的認(rèn)知邏輯的。但是面對(duì)這樣的問題,我們?cè)撊绾翁幚砟??我們希望異常樣本和正常樣本的?shù)量一樣多,這樣機(jī)器就會(huì)認(rèn)為它們同等重要。要實(shí)現(xiàn)正常樣本和異常樣本數(shù)量一樣多,有兩種方案:

1.下采樣:

從多數(shù)的正常樣本中隨機(jī)選出與少數(shù)樣本一樣多的數(shù)據(jù),組成新的數(shù)據(jù)集,然后進(jìn)行建模任務(wù)。這里,我們以銀行貸款數(shù)據(jù)集作為例子,該數(shù)據(jù)集已經(jīng)做過了脫敏(去敏感信息)處理。
creditcard:鏈接:https://pan.baidu.com/s/1t5opuhFew5xVP2zpIwfmVA
提取碼:khj6
具體實(shí)現(xiàn)過程:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

df = pd.read_csv('D:\\Py_dataset\\creditcard.csv')
df.head()#打印出前五行數(shù)據(jù)進(jìn)行觀察

print('該數(shù)據(jù)集規(guī)模:',df.shape)
該數(shù)據(jù)集規(guī)模: (284807, 31)

df['Class'].value_counts()
0    284315
1       492
Name: Class, dtype: int64

#樣本分布可視乎
df['Class'].value_counts(normalize = True).plot(kind = 'bar')

前五行數(shù)據(jù)信息:


creditcard data.png

樣本分布比例:


imblanced data.png

下采樣方案代碼實(shí)現(xiàn):

#異常樣本的個(gè)數(shù)
fraud_number = len(df[df.Class == 1])

#異常樣本的索引
fraud_indices = df[df.Class == 1].index
fraud_indices = np.array(fraud_indices)

#正常樣本的索引
norm_indices = df[df.Class == 0].index
norm_indices = np.array(norm_indices)

#在所有正常樣本中選出與異常樣本個(gè)數(shù)一樣多的樣本索引
undersample_norm_indices = np.random.choice(norm_indices,fraud_number,replace = False)
undersample_norm_indices = np.array(undersample_norm_indices)

#將下采樣正常樣本的索引和異常樣本的索引進(jìn)行組合
undersample_indices = np.concatenate((fraud_indices,undersample_norm_indices))
#下采樣的樣本
undersample_data = df.loc[undersample_indices,:]

#查看下采樣正常樣本和異常樣本的分布
print('下采樣數(shù)據(jù)集的大小:',undersample_indices.shape[0])
print('下采樣數(shù)據(jù)集正樣本的個(gè)數(shù):',undersample_data[undersample_data.Class == 0].shape[0])
print('下采樣數(shù)據(jù)集負(fù)樣本的個(gè)數(shù):',undersample_data[undersample_data.Class == 1].shape[0])
下采樣數(shù)據(jù)集的大小: 984
下采樣數(shù)據(jù)集正樣本的個(gè)數(shù): 492
下采樣數(shù)據(jù)集負(fù)樣本的個(gè)數(shù): 492

2.過采樣:

讓異常樣本的數(shù)量與正常樣本一樣多,這就需要對(duì)少數(shù)樣本進(jìn)行生成,這里的生成可不是復(fù)制,一模一樣的樣本是沒有用的。最長用的就是SMOTE數(shù)據(jù)生成算法。

SMOTE算法的流程如下:

  • 1.對(duì)于少數(shù)類中的每一個(gè)樣本x,以歐式距離為標(biāo)準(zhǔn),計(jì)算它到少數(shù)樣本集中所有樣本的距離,經(jīng)過排序,得到其近鄰樣本。
  • 2.根據(jù)樣本不平衡比例設(shè)置一個(gè)采樣倍率N,對(duì)于每一個(gè)少數(shù)樣本x,從其近鄰依次選擇N個(gè)樣本,如圖(a)所示。
  • 3.對(duì)于每一個(gè)選出的近鄰樣本,分別與原樣本按照如下的公式構(gòu)建新的樣本數(shù)據(jù)。其中x為少數(shù)樣本,x^ 為少數(shù)樣本x的近鄰樣本,從0~1之間選擇一個(gè)隨機(jī)數(shù)乘以x與近鄰樣本x的距離再加上x,即可得到x與x之間的新樣本,如圖(b)所示。
    SMOTE function.jpg

    SMOTE sample.jpg

SMOTE算法代碼實(shí)現(xiàn):
對(duì)于SMOTE算法,可以使用imblearn這個(gè)工具包來完成,首先需要在prompt命令行中安裝該工具包(pip install imblearn)。對(duì)于SMOTE算法而言,只需要傳入特征和標(biāo)簽即可得到一個(gè)大量的異常樣本集。

#提取標(biāo)簽
labels = df['Class']
#提取特征
features = df.drop('Class',axis = 1)

#導(dǎo)入SMOTE算法
from imblearn.over_sampling import SMOTE
oversampler = SMOTE(random_state = 0)
os_features,os_labels = oversampler.fit_sample(features,labels)

#查看原始數(shù)據(jù)集中正常和異常樣本的分布
print('原始數(shù)據(jù)集正常樣本的個(gè)數(shù):',df[df['Class'] == 0].shape[0])
print('原始數(shù)據(jù)集異常樣本的個(gè)數(shù):',df[df['Class'] == 1].shape[0])
print('原始數(shù)據(jù)集的長度:',df.shape[0])
原始數(shù)據(jù)集正常樣本的個(gè)數(shù): 284315
原始數(shù)據(jù)集異常樣本的個(gè)數(shù): 492
原始數(shù)據(jù)集的長度: 284807

#新構(gòu)造的數(shù)據(jù)集中正常樣本和異常樣本的分布
print('過采樣數(shù)據(jù)集中正常樣本的個(gè)數(shù):',len(os_labels[os_labels == 0]))
print('過采樣數(shù)據(jù)集中異常樣本的個(gè)數(shù):',len(os_labels[os_labels == 1]))
print('過采樣數(shù)據(jù)集的長度:',len(os_labels))
過采樣數(shù)據(jù)集中正常樣本的個(gè)數(shù): 284315
過采樣數(shù)據(jù)集中異常樣本的個(gè)數(shù): 284315
過采樣數(shù)據(jù)集的長度: 568630

從結(jié)果中可以看出異常樣本的數(shù)量從492個(gè)變成了284315個(gè),與正常樣本的數(shù)量一致。

這一小節(jié),我們總結(jié)了處理樣本不均衡數(shù)據(jù)集的兩種方法,下采樣和過采樣。其中不涉及數(shù)據(jù)的預(yù)處理、建模以及模型評(píng)估等內(nèi)容。在具體的任務(wù)當(dāng)中,采樣方案與數(shù)據(jù)預(yù)處理、建模、模型評(píng)估,參數(shù)優(yōu)化構(gòu)成了一個(gè)整體。

3.采樣方案總結(jié):

  • 1.下采樣方案比較簡單,從多數(shù)樣本中隨機(jī)選擇與少數(shù)樣本一樣多的數(shù)據(jù),方便我們處理樣本不均衡數(shù)據(jù)。但下采樣方案犧牲了原有數(shù)據(jù)的豐富性,只使用了一小部分的數(shù)據(jù)。
    1. 過采樣方案,通過數(shù)據(jù)生成策略,使得異常樣本的數(shù)量與正常樣本一樣多,方便我們處理樣本不均衡數(shù)據(jù)。但生成的數(shù)據(jù)畢竟是不真實(shí)的,是通過一定的規(guī)則偽造出來的。
  • 3.下采樣方案和過采樣各有優(yōu)缺點(diǎn),在處理具體的任務(wù)時(shí),需通過實(shí)驗(yàn)對(duì)比兩種方案的優(yōu)劣。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容