smote算法_探索SMOTE算法
SMOTE是一種綜合采樣人工合成數(shù)據(jù)算法,用于解決數(shù)據(jù)類別不平衡問題(Imbalanced class problem),以O(shè)ver-sampling少數(shù)類和Under-sampling多數(shù)類結(jié)合的方式來合成數(shù)據(jù)。本文將以 Nitesh V. Chawla(2002) 的論文為藍(lán)本,闡述SMOTE的核心思想以及實(shí)現(xiàn)其樸素算法,在傳統(tǒng)分類器(貝葉斯和決策樹)上進(jìn)行對比算法性能并且討論其算法改進(jìn)的途徑。
1. 引言
類別不平衡是一種在分類器模型訓(xùn)練過程中常見的問題之一,如通過大量胸透圖片來學(xué)習(xí)判斷一個(gè)人是否有癌癥,又如在網(wǎng)絡(luò)流日志中學(xué)習(xí)檢測可能是攻擊行為的數(shù)據(jù)模式,這一類的任務(wù)中都是正常的類多于異常(診斷屬于癌癥,屬于攻擊行為)的類,在類別不平衡數(shù)據(jù)下訓(xùn)練出來的分類器要非常的小心,即使該分類器擁有很高的精度,因?yàn)樗芸赡軙?xí)得大部分的都是正常的,而我們可能需要的是它能夠最大程度的識別異常行為,哪怕精度低于前者。
為了解決這一問題,業(yè)內(nèi)已經(jīng)有以下5種公認(rèn)的方法去擴(kuò)充數(shù)據(jù)集[1],以至于類別均勻:
- 隨機(jī)的增大少數(shù)類的樣本數(shù)量。
- 隨機(jī)的增大特定少數(shù)類樣本的數(shù)量。
- 隨機(jī)的減少多數(shù)類樣本的數(shù)量。
- 隨機(jī)的減少特定多數(shù)類樣本的數(shù)量。
- 修改代價(jià)函數(shù),使得少數(shù)類出錯(cuò)的代價(jià)更高。
本文要介紹的SMOTE算法就是一種綜合1,3方法的改進(jìn)方式,它以每個(gè)樣本點(diǎn)的k個(gè)最近鄰樣本點(diǎn)為依據(jù),隨機(jī)的選擇N個(gè)鄰近點(diǎn)進(jìn)行差值乘上一個(gè)[0,1]范圍的閾值,從而達(dá)到合成數(shù)據(jù)的目的。這種算法的核心是:特征空間上鄰近的點(diǎn)其特征都是相似的。它并不是在數(shù)據(jù)空間上進(jìn)行采樣,而是在特征空間中進(jìn)行采樣,所以它的準(zhǔn)確率會高于傳統(tǒng)的采樣方式。這也是為什么到目前為止SMOTE以及其派生的算法仍然是較為主流的采樣技術(shù)的原因。
如上圖所示,假設(shè)數(shù)據(jù)點(diǎn)A在特征空間上有4個(gè)鄰近點(diǎn),若N為2,則SMOTE會隨機(jī)選擇其中2個(gè)鄰近點(diǎn)B,C,分別計(jì)算A->B, A->C的距離,如圖中綠線和紅線所示,在綠線或紅線上的所有采樣點(diǎn)都是合理的,如點(diǎn)A1。為了確保數(shù)據(jù)點(diǎn)盡可能的多樣(不重疊),故乘上一個(gè)[0, 1]之間的隨機(jī)因子。
本文將會在第2章根據(jù)SMOTE的核心以及其偽代碼實(shí)現(xiàn)該算法,并應(yīng)用在測試數(shù)據(jù)集上;第3章會使用第三方 imbalanced-learn 庫中實(shí)現(xiàn)的SMOTE算法進(jìn)行采樣,以驗(yàn)證我們實(shí)現(xiàn)的算法的準(zhǔn)確性,當(dāng)然這個(gè)庫中的算法要優(yōu)于樸素的SMOTE算法,之后我們會以決策樹和高斯貝葉斯分類器為工具,對測試原始數(shù)據(jù)、應(yīng)用我們所實(shí)現(xiàn)的SMOTE采樣后產(chǎn)生的數(shù)據(jù)以及應(yīng)用第三方庫SMOTE產(chǎn)生的數(shù)據(jù)三者分別產(chǎn)生的數(shù)據(jù)集進(jìn)行性能比較;第4章會討論樸素SMOTE算法更加魯棒和表現(xiàn)更好的優(yōu)化途徑;第5章是對本文的總結(jié)。
2. 算法分析與實(shí)現(xiàn)
下圖是在SMOTE論文中提出的偽代碼,由兩個(gè)函數(shù) SMOTE(T, N, K) 和 Populate(N, i, nnarray) 組成。
SMOTE 負(fù)責(zé)接受要采樣的類數(shù)據(jù)集X,返回一個(gè)經(jīng)過SMOTE采樣后的數(shù)據(jù)集,大小為 (N/100)*T ,函數(shù)有三個(gè)參數(shù),分別是 T: 需要處理的數(shù)據(jù)集X的樣本數(shù)量; N: 采樣比例,一般為100, 200, 300等整百數(shù),對應(yīng)即1倍,2倍,3倍;K: 為采樣的最近鄰數(shù)量,論文中默認(rèn)為5 。 SMOTE 代碼思想非常簡單,掃描每一個(gè)樣本點(diǎn),計(jì)算每一個(gè)樣本點(diǎn)的K個(gè)最近鄰,將每一個(gè)最近鄰樣本點(diǎn)的索引記錄在 nnarray 中,之后傳入 Populate(N, i, nnarray) 中即完成一個(gè)樣本點(diǎn)的采樣。
Populate 則負(fù)責(zé)根據(jù) nnarray 中的索引去隨機(jī)生成 N 個(gè)與觀測樣本 i 相似的樣本。該函數(shù)會計(jì)算隨機(jī)鄰近點(diǎn) nn 與觀測樣本 i 點(diǎn)的每一個(gè)特征之間的差距 dif ,將其差距乘上一個(gè)[0, 1]隨機(jī)因子 gap ,再將 dif*gap 的值加上觀測點(diǎn) i 即完成了一個(gè)特征的合成。
在Python中實(shí)現(xiàn)如下:
注:為了保證本文中所有代碼的可復(fù)現(xiàn)性,設(shè)置的 random_state 均為 666
def NaiveSMOTE(X, N=100, K=5): """ {X}: minority class samples; {N}: Amount of SMOTE; default 100; {K} Number of nearest; default 5; """ # {T}: Number of minority class samples; T = X.shape[0] if N < 100: T = (N/100) * T N = 100 N = (int)(N/100) numattrs = X.shape[1] samples = X[:T] neigh = NearestNeighbors(n_neighbors=K) neigh.fit(samples) Synthetic = np.zeros((T*N, numattrs)) newindex = 0 def Populate(N, i, nns, newindex): """ Function to generate the synthetic samples. """ for n in range(N): nn = np.random.randint(0, K) for attr in range(numattrs): dif = samples[nns[nn], attr] - samples[i, attr] gap = np.random.random() Synthetic[newindex, attr] = samples[i, attr] + gap*dif newindex += 1 return newindex for i in range(T): nns = neigh.kneighbors([samples[i]], K, return_distance=False) newindex = Populate(N, i, nns[0], newindex) return Synthetic
這里沒有采用矩陣運(yùn)算,而是完完全全的按照論文中的方式復(fù)現(xiàn)(所以稱為NaiveSMOTE),其中最近鄰的計(jì)算我們使用 scikit-learn 提供的 NearestNeighbors 類完成。
接下來我們使用 scikit-learn 中的 make_classification 來生成測試分類數(shù)據(jù)集,模擬不平衡類數(shù)據(jù),當(dāng)然有興趣的讀者也可以去尋找論文中所使用的數(shù)據(jù)集。
from sklearn.datasets import make_classificationX, y = make_classification(n_samples=500, n_features=9, n_redundant=3, weights=(0.1, 0.9), n_clusters_per_class=2, random_state=666) # 為了可復(fù)現(xiàn)性print(X.shape, y.shape) # ((500, 9), (500,))# 查看y的各類樣本數(shù) print(view_y(y)) # class 0: 50 class 1: 450
原數(shù)據(jù)集的分布如下圖所示,其中紅色圓圈為正類即少數(shù)類,藍(lán)色×為負(fù)類即多數(shù)類。
將我們實(shí)現(xiàn)的 NaiveSMOTE 應(yīng)用在此測試數(shù)據(jù)上:
X_over_sampling = NaiveSMOTE(X[y==0], N=800)print(X_over_sampling.shape) # (400, 9) 新增了400個(gè)樣本# 將合成數(shù)據(jù)與原數(shù)據(jù)集合并new_X = np.r_[X, X_over_sampling]new_y = np.r_[y, np.zeros((X_over_sampling.shape[0]))]print(new_X.shape, new_y.shape) # ((900, 9), (900,))print(view_y(new_y)) # class 0: 450 class 1: 450
接下來我們將原數(shù)據(jù)集與經(jīng)過 NaiveSMOTE 合成后的數(shù)據(jù)集進(jìn)行比對:
可以很清晰的看見原來的類增大至一個(gè)滿意的水平,并且生成的類之間距離都相距不遠(yuǎn)。
3. 算法性能比對
本章我們將引入第三方庫 imbalanced-learn 中提供的 SMOTE 類與依據(jù)論文實(shí)現(xiàn)的 NaiveSMOTE 進(jìn)行比較。兩者都是基于同一個(gè)論文的思想去實(shí)現(xiàn)的,只是第三方庫中實(shí)現(xiàn)的 SMOTE 更為魯棒,并且能夠綜合考慮所有的類,是一種完全意義上的 Combination of Over-sampling minority class and Under-sampling majority class 技術(shù)。因此我們引入它只為了驗(yàn)證我們所復(fù)現(xiàn)的方法的準(zhǔn)確性。
from imblearn.over_sampling import SMOTEsm = SMOTE(random_state=666)X_res, y_res = sm.fit_resample(X, y) # 即完成了合成print(X_res.shape, y_res.shape) # ((900, 9), (900,))
下圖對比 imblearn 的 SMOTE 與我們復(fù)現(xiàn)的 NaiveSMOTE 生成的數(shù)據(jù)集:
能看出 NaiveeSMOTE 合成的數(shù)據(jù)更加傾向于中部,而第三方的 SMOTE 能夠綜合考慮全局情況下方區(qū)域生成的數(shù)據(jù)要比 NaiveSMOTE 的多。
接下來我們使用 DecisionTree 和 GaussianNaive 來驗(yàn)證3個(gè)數(shù)據(jù)集(原數(shù)據(jù)集、NaiveSMOTE合成的數(shù)據(jù)集和第三方SMOTE合成的數(shù)據(jù)集)的ROC曲線,具體代碼見附錄中的 Notebook 文件
原數(shù)據(jù)的ROC曲線
NaiveSMOTE生成的數(shù)據(jù)的ROC曲線
第三方SMOTE生成的數(shù)據(jù)的ROC曲線
可以看出 NaiveSMOTE 與 imblearn 的 SMOTE 生成的數(shù)據(jù)的 AUC 面積均大于原始數(shù)據(jù)的面積。 imblearn 的 SMOTE 生成的數(shù)據(jù)在 GaussianNaiveBayes 分類器上的表現(xiàn)要好于 NaiveSMOTE 所生成的數(shù)據(jù)訓(xùn)練出來的分類器。
4. 算法改進(jìn)
這部分我們從 NaiveSMOTE 的三個(gè)方面進(jìn)行優(yōu)化討論:
- 處理速度。 NaiveSMOTE 中有許多處都可以改成使用矩陣運(yùn)算的方式,這樣會提高數(shù)據(jù)處理的速度。并且 Populate 函數(shù)也顯得非常冗余,可以用矩陣運(yùn)算將其改寫。
- 全局合理性。 全局合理性包括兩個(gè)方面:合成數(shù)據(jù)比率的合理性和合成數(shù)據(jù)在全局的合理性。合成數(shù)據(jù)比率的合理性:在 NaiveSMOTE 中可以知道樣本的數(shù)量有 N 合成比率來控制,只能合成其整數(shù)倍,本文中使用的數(shù)據(jù)集恰好是 1:9 ,只要合成原始數(shù)據(jù)的8倍即可是兩類都到達(dá)一個(gè)相對數(shù)量同等的水平,但是在現(xiàn)實(shí)數(shù)據(jù)集中大部分都不具備成倍的數(shù)量關(guān)系,因此可以考慮更換一個(gè)更好的生成比率,使得每個(gè)類均能處于相對數(shù)量近似的水平,避免出現(xiàn)合成后的原少數(shù)類變多數(shù)類的情況。合成數(shù)據(jù)在全局的合理性:回想在 NaiveSMOTE 與 imblearn SMOTE 各自合成的數(shù)據(jù)對比中可以發(fā)現(xiàn), NaiveSMOTE 更加容易使得合成的數(shù)據(jù)聚集在某一樣本點(diǎn)附近,而 imblearn SMOTE 所合成的數(shù)據(jù)更為稀疏且分布均勻,更加接近原始數(shù)據(jù)的概率分布。其原因在于 NaiveSMOTE 在進(jìn)行合成時(shí)只考慮原始的數(shù)據(jù)樣本,沒不考慮合成后的數(shù)據(jù)樣本會如何影響全局?jǐn)?shù)據(jù)。可以考慮在每次合成數(shù)據(jù)后將其加入數(shù)據(jù)集,在處理過程中將合成數(shù)據(jù)也加入考慮范圍。
- 魯棒性。 不難發(fā)現(xiàn) NaiveSMOTE 僅能夠處理數(shù)值型的數(shù)據(jù)并且其距離計(jì)算公式很有可能產(chǎn)生誤解。在現(xiàn)實(shí)中有許多非數(shù)值型的數(shù)據(jù),如 性別 , 職業(yè) 等等。當(dāng)然可以將其全部重新編碼成可以應(yīng)用數(shù)值處理的數(shù)據(jù),如將性別進(jìn)行 OneHot 編碼,但是此時(shí)的距離計(jì)算公式就會出現(xiàn)誤解,可以考慮更換為歐氏距離、曼哈頓距離或者馬氏距離等。
Note:在對性別進(jìn)行 OneHot 編碼時(shí)情況如下:
男性: 0 1女性: 1 0
如果按照 NaiveSMOTE 原始的距離計(jì)算公式,很有可能會將其理解為男性和女性的差距為1,因此產(chǎn)生誤解。
5. 結(jié)論
本文對三種數(shù)據(jù)進(jìn)行對比,經(jīng)過 NaiveSMOTE 和 imblearn SMOTE 合成后的數(shù)據(jù)在傳統(tǒng)分類器上的表現(xiàn)均好于原始數(shù)據(jù)(即不做任何修改),且 imblearn SMOTE 在魯棒性上要高于 NaiveSMOTE 。討論 NaiveSMOTE 的不足與其可能的優(yōu)化方向。建議在實(shí)際應(yīng)用中優(yōu)先考慮魯棒性更高的 imlearn SMOTE 而不是自己造輪子, imblearn SMOTE 的實(shí)現(xiàn)更加符合主流標(biāo)準(zhǔn)。但不能因此就忽略了 NaiveSMOTE 的意義,任何的優(yōu)化有必要要基于原有的基礎(chǔ)。理解 NaiveSMOTE 才能去更好的使用和優(yōu)化它。
總結(jié)
以上是生活随笔為你收集整理的smote算法_探索SMOTE算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一般过去时教学设计一等奖
- 下一篇: 法院“惩戒失信,弘扬诚信”宣传标语文案2