読者です 読者をやめる 読者になる 読者になる

マイノリティ合成によるオーバー・サンプリング

 今回は、不均衡データの分類に挑戦します。*1 最もシンプルな不均衡データへの対処としては、復元抽出によって、マイナークラスの標本数を増やすことが挙げられます。しかし、同じ標本が複数含まれることによって、過学習を引き起こしやすくなると言われています。*2 そのため、手元の標本を単に複製するのではなく、近傍データを使って新たな標本を作成するというアプローチがよく取られます。このような手法は、SMOTE (Synthetic Minority Over-sampling Technique) と呼ばれています。*3
 RでSMOTEを実行するには、DMwRパッケージのSMOTE関数を使います。以下の例では、irisデータの一部を使って、線形判別分析による分類を行っています。

# irisから一部のデータを抽出
my.iris <- rbind(iris[1 : 50, ], iris[51 : 80, ], iris[101 : 110, ])
# 標本数を確認
table(my.iris[, 5])

 上記のスクリプトを実行すると、以下のような結果が得られます。

setosa versicolor  virginica 
    50         30         10 

 まずは、このデータに対して、普通に線形判別分析を行ってみます。

# 線形判別分析
library(MASS)
res <- lda(Species ~ ., data = my.iris, CV = TRUE)
tab <- table(my.iris[, 5], res$class)
sum(diag(tab)) / sum(tab)

 上記のスクリプトを実行すると、以下のような分類精度が得られます。

[1] 0.9888889

 次に、上記のデータに対して、SMOTEを行ってみましょう。*4

# SMOTE
library(DMwR)
set.seed(1)
my.iris.smote <- SMOTE(Species ~ ., data = my.iris, perc.over = 200, k = 5, perc.under = 200)
# 標本数を確認
table(my.iris.smote[, 5])

 上記のスクリプトを実行すると、以下のような結果が得られます。SMOTEによって、クラス間の標本数の差が小さくなりました。

setosa versicolor  virginica 
    23         17         30 

 では、このデータに対して、線形判別分析を行ってみます。

# 線形判別分析
res2 <- lda(Species ~ ., data = my.iris.smote, CV = TRUE)
tab2 <- table(my.iris.smote[, 5], res2$class)
sum(diag(tab2)) / sum(tab2)

 上記のスクリプトを実行すると、以下のような分類精度が得られます。精度が向上しました。

[1] 1

 同様に、kernlabパッケージのspamデータの一部を使って、線形判別分析による分類を行ってみます。

# spamから一部のデータを抽出
library(kernlab)
data(spam)
my.spam <- rbind(head(spam, 500), tail(spam, 2500))
# 標本数を確認
table(my.spam[, 58])

 上記のスクリプトを実行すると、以下のような結果が得られます。

nonspam    spam 
   2500     500 

 では、この不均衡なspamデータに対して、SMOTEを行ってみましょう。

# SMOTE
set.seed(1)
my.spam.smote <- SMOTE(type ~ ., data = my.spam, perc.over = 200, k = 5, perc.under = 200)
# 標本数を確認
table(my.spam.smote[, 58])

 上記のスクリプトを実行すると、以下のような結果が得られます。

nonspam    spam 
   2000    1500

 そして、この2種類のspamデータに対して、線形判別分析による分類を行ってみます。

# 不均衡なspamデータに線形判別分析
res3 <- lda(type ~ ., data = my.spam, CV = TRUE)
tab3 <- table(my.spam[, 58], res3$class)
# SMOTEを行ったspamデータに線形判別分析
res4 <- lda(type ~ ., data = my.spam.smote, CV = TRUE)
tab4 <- table(my.spam.smote[, 58], res4$class)
# 分類精度の確認
sum(diag(tab3)) / sum(tab3)
sum(diag(tab4)) / sum(tab4)

 上記のスクリプトを実行すると、以下のような分類精度が得られます。やはり、SMOTEを行ったデータの方が高い精度となっています。*5

# 元の不均衡データ
[1] 0.907
# SMOTEを行ったデータ
[1] 0.9145714

*1:不均衡データについては最近勉強を始めたばかりなので、間違いや不適切な表現があるかも知れません。

*2:詳しくは、『経営と信用リスクのデータ科学』の第10章を参照。今回の記事は、基本的に、この本で勉強したことに基づいて書かれています。そして、この記事を書いたあとで、『データ分析プロセス』の第4章にも不均衡データに関する記述があることを発見しました。

*3:SMOTEについては、Chawla, N. V., et al. (2002). SMOTE: Synthetic Minority Over-sampling Technique. Journal of Artificial Intelligence Research, 16, 321–357を参照。

*4:引数で指定するパラメータの値は、適当に指定しているため、最適なものではない可能性があります。因みに、引数perc.overではマイナークラスの標本をどれだけ増加させるか、引数kではサンプリングにいくつの近傍データを使うか、引数perc.underではメジャークラスの標本をどれだけ抽出するか、を指定します。

*5:当然、クラス間の標本数を近付けたにもかかわらず、何らかの理由で分類精度が下がる場合もあります。