解決R語言 數據不平衡的問題

R語言解決數據不平衡問題

一、項目環境

開發工具:RStudio

R:3.5.2

相關包:dplyr、ROSE、DMwR

二、什麼是數據不平衡?為什麼要處理數據不平衡?

首先我們要知道的第一個問題就是“什麼是數據不平衡”,從字面意思上進行解釋就是數據分佈不均勻。在我們做有監督學習的時候,數據中有一個類的比例遠大於其他類,或者有一個類的比值遠小於其他類時,我們就可以認為這個數據存在數據不平衡問題。

那麼這樣的一個問題會對我們後續的分析工作帶來怎樣的影響呢?我舉個簡單的例子,或許大傢就明白瞭。

假設我們現在需要訓練一個模型來分辨人群中那個人是恐怖分子。那麼現在給到我們1萬個人員的數據,在做分析之前其實我們就很清楚,一群人中恐怖分子的比例肯定是要遠小於普通人的比例的。

那麼假如在這1萬個人中隻有一個是恐怖分子,那麼恐怖分子與正常人的比例就是 9999 : 1 。

那麼如果我們不進行任何處理就直接進行有監督學習的話,那麼模型隻需要將所有人數據都分類為正常人,模型的準確率就能達到99.99%。而這樣的模型顯然是沒有意義的。

因為基本上說有可能存在的恐怖分子的特征基本都被模型給忽略瞭,這也就說明瞭為什麼要處理數據不平衡問題。

三、 常見的數據不平衡處理方法

以下是幾種比較常見的處理數據不平衡的方法:

1、欠采樣法(Undersampling)

2、過采樣法(Oversampling)

3、人工數據合成法(Synthetic Data Generation)

4、代價敏感學習法(Cose Sensitive Learning)

【註】:本文主要以實現為主,因此不對上述方法進行過多的講解。

​ 在處理數據之前,我們先看一下需要處理的數據分佈的情況。

load("C:/Users/User/Desktop/data.RData")
table(data$classification)
prop.table(table(data$classification))

> table(data$classification)

-8 1 2 3 4 5

12 104 497 1158 4817 1410

> prop.table(table(data$classification))

-8 1 2 3 4 5

0.001500375 0.013003251 0.062140535 0.144786197 0.602275569 0.176294074

1、 欠采樣

######### 方法一 #########
library(ROSE)
# 由於是多分類問題,我們先提取數據中比例最大的類和比例最小的類
# 進行平衡(轉化為二分類問題)
test <- data[which(data$classification == -8 | data$classification == 4),]
# 將分類結果轉化為因子型(不然會報錯)
test$classification <- as.factor(test$classification)
# 進行欠采樣
# 其中 method = "under" 表示采用的方法為“欠采樣”
# N = 40 表示最終整個數據集的數量
# seed 隨機種子,為瞭保留對樣本的追蹤
under <- ovun.sample(classification ~ ., test, method = "under", N = 40, seed = 1)$data
# 查看結果
table(under$classification)

> table(under$classification)

4 -8

28 12

######### 方法二 #########
library(dplyr)
# 由於是多分類問題,我們先提取數據中比例最大的類和比例最小的類
# 進行平衡(轉化為二分類問題)
test <- data[which(data$classification == -8 | data$classification == 4),]
# 提取大比例類
test1 <- test[which(test$classification == 4),]
# 將大比例類的數量降為12個
down <- sample_n(test1, 12, replace = TRUE)
# 將欠采樣後的類進行合並
down <- rbind(test[which(test$classification == -8), ],down)
table(down$classification)

> table(down$classification)

-8 4

12 12

【註】:欠采樣是無放回的采樣。

2、 過采樣

######### 方法一 #########
library(ROSE)
test <- data[which(data$classification == -8 | data$classification == 4),]
test$classification <- as.factor(test$classification)
# 實現上大致與欠采樣相同,隻有類型 method 改成瞭 "over",同時沒有限制總數量
under <- ovun.sample(classification ~ ., test, method = "over", seed = 1)$data
table(under$classification)

> table(under$classification)

4 -8

4817 4785

######### 方法二 #########
library(dplyr)
test <- data[which(data$classification == -8 | data$classification == 4),]
# 提取小比例類
test1 <- test[which(test$classification == -8),]
# 將小比例類的數量降為4817個(與大比例類相同)
# 這裡使用的過采樣方法是隨機復制小比例類中的數據,將其擴充到指定數量
down <- sample_n(test1, 4817, replace = TRUE)
down <- rbind(test[which(test$classification == 4), ],down)
table(down$classification)

> table(down$classification)

-8 4

4817 4817

3、人工數據合成法(Synthetic Data Generation)

######### 方法一 #########
library(ROSE)
# 由於是多分類問題,我們先提取數據中比例最大的類和比例最小的類
# 進行平衡(轉化為二分類問題)
test <- data[which(data$classification == -8 | data$classification == 4),]
# 將分類結果轉化為因子型(不然會報錯)
test$classification <- as.factor(test$classification)
# ROSE提供瞭ROSE()函數來合成人工數據
rose <- ROSE(classification ~ ., test, seed = 1)$data
# 查看結果
table(rose$classification)

> table(rose$classification)

4 -8

2483 2346

######### 方法二 #########
library(DMwR)
test <- data[which(data$classification == -8 | data$classification == 4),]
test$classification <- as.factor(test$classification)
# perc.over: 如 perc.over = n,小比例類的個數變為 (n/100)a + a 個數據(a為小比例類原始數量)
# perc.under: 如 perc.under = m,大比例類的個數變為((nm)/100)a個
# 因此本次案例中,小比例類的個數變為(3500/100)*12 + 12 = 432個
# 大比例類的個數變為((3500*300)/100^2)*12 = 1260個
down <- SMOTE(classification ~ ., test, perc.over = 3500, perc.under = 300)
table(down$classification)

> table(down$classification)

-8 4

432 1260

【註】:相較於前兩種方法而言,人工合成法既不會像過采樣容易導致過擬合問題,也不會出現欠采樣大量丟失信息的問題。

4、代價敏感學習法(Cose Sensitive Learning)

【註】:還沒想好怎麼寫。。。。。

三、 結語

本文之所以都隻拿兩個分類在進行分析,是因為上面提到的用於解決數據不平衡問題的函數,基本上都是針對二分類問題的。當導入的數據中有大於兩個分類時,函數就會報錯。

但是在實際分析的過程中,其實我們更經常遇到的時多分類問題,這是我們就需要將多分類問題轉化為二分類問題,將各個分類兩兩進行比較才能更好的解決數據不平衡的問題。

推薦閱讀: