Top Banner
不均衡データのクラス分類 2012年1月28日 第20回Tokyo.R @sfchaos
34

不均衡データのクラス分類

Jan 15, 2015

Download

Technology

sfchaos

 
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 不均衡データのクラス分類

不均衡データのクラス分類

2012年1月28日第20回Tokyo.R

@sfchaos

Page 2: 不均衡データのクラス分類

アジェンダ

自己紹介

クラス分類

不均衡データ

不均衡データへの対処方法

Page 3: 不均衡データのクラス分類

1. 自己紹介

TwitterID:@sfchaos

お仕事:データ分析

Page 4: 不均衡データのクラス分類

2. クラス分類

Page 5: 不均衡データのクラス分類

クラス分類とは,

データの特徴に基づき

データが属するクラスを

推定する問題

Page 6: 不均衡データのクラス分類

例えば,

スパムメールの判別

重病の罹患有無の判別

Page 7: 不均衡データのクラス分類

クラス分類を行うための手法は数多く提案されている.

決定木

ナイーブベイズ

サポートベクタマシン

ブースティング

ランダムフォレスト etc.

Page 8: 不均衡データのクラス分類

クラス分類のアルゴリズムは

一般に多クラスの分類に対応

しかし,今回は2クラスの

分類問題だけを扱う

正例・・・興味のあるクラス

負例・・・興味のないクラス

Page 9: 不均衡データのクラス分類

3. 不均衡データ

Page 10: 不均衡データのクラス分類

クラスに属するサンプル数に

偏りがあるデータを

「不均衡データ」と呼ぶ

※英語では"imbalanced data"

Page 11: 不均衡データのクラス分類

現実の問題では,

クラスのサンプル数が

偏っていることは多い

また,興味のあるクラスは

サンプル数が少ないことも多い

Page 12: 不均衡データのクラス分類

こうしたデータに対して

工夫もせずに

クラス分類をしようとすると・・・

Page 13: 不均衡データのクラス分類

> library(kernlab)

> # データの読み込み(データは"../data/"ディレクトリに置いておく)

> abalone <- read.csv("../data/abalone.data", header=FALSE)

> # 19番目のクラスを正例に,それ以外のクラスを負例とする

> label <- abalone[, 9]

> label[label==19] <- "positive"

> label[label!="positive"] <- "negative"

> label <- factor(label)

> table(label)

label

negative positive

4145 32 正例32サンプル,負例4145サンプルのデータ

Page 14: 不均衡データのクラス分類

> set.seed(123)

> # クロスバリデーションの実行(多項式カーネルを用い,次数は2とする)

> idx <- sample(1:10, nrow(abalone), replace=TRUE)

> for (i in 1:10) {

+ is.test <- idx == i

+ abalone.train <- abalone[!is.test, ]

+ abalone.test <- abalone[is.test, -9]

+ fit.ksvm <- ksvm(label ~., data=abalone.train, kernel="polydot", kpar=list(degree=2))

+ pred[is.test] <- as.character(predict(fit.ksvm, abalone.test))

+ }

> # 予測結果の集計

> table(pred)

pred

negative

4177

全てを負例と判別!!

Page 15: 不均衡データのクラス分類

4. 不均衡データへの

対処方法

Page 16: 不均衡データのクラス分類

不均衡なデータへの対処方法は,

大きく分けて2つある

Page 17: 不均衡データのクラス分類

①正例を誤答したときの

ペナルティを重くする

(cost-sensitive learning)

②正例と負例のサンプル数を

調整する

Page 18: 不均衡データのクラス分類

①正例を誤答したときの

ペナルティを重くする

(cost-sensitive learning)

SVMでは,

ksvm関数(kernlabパッケージ)のclass.weights引数に指定

Page 19: 不均衡データのクラス分類

> label.table <- table(label)> # 正例の重み(負例と正例のサンプル数の比とする)> weight.positive <- as.numeric(label.table[1]/label.table[2])> # 10-fold クロスバリデーションの実行> for (i in 1:10) {+ is.test <- idx == i+ abalone.train <- abalone[!is.test, ]+ abalone.test <- abalone[is.test, -9]+ fit.ksvm <- ksvm(label ~., data=abalone.train, + class.weights=c("positive"=weight.positive, + "negative"=1), + kernel="polydot", kapr=list(degree=2))+ pred[is.test] <- as.character(predict(fit.ksvm, abalone.test))+ }> table(label, pred) pred label negative positive negative 3118 1027 positive 19 13

何も工夫しないよりは良くなったが,まだまだ(モデルパラメータのチューニングの余地もまだまだあり)

正例と負例のサンプル数に反比例したペナルティの重みを指定

Page 20: 不均衡データのクラス分類

②正例と負例のサンプル数を調整する

オーバーサンプリング →正例を増やす

アンダーサンプリング  →負例を減らす

両方

Page 21: 不均衡データのクラス分類

いろいろなアルゴリズムが

提案されているが,

Rで簡単に試せるのは

DMwRパッケージのSMOTE

Page 22: 不均衡データのクラス分類

SMOTEでは,

正例を人工的に作成

(オーバーサンプリング),

負例をアンダーサンプリングする

Page 23: 不均衡データのクラス分類

> library(kernlab)> library(DMwR)> set.seed(123)> # 元のデータにサンプル名の付値> rownames(abalone) <- paste("original",

1:nrow(abalone), sep="")> # SMOTE関数を用いて人工的な正例の生成,負例をアンダー

サンプリング> abalone.smote <- ++ SMOTE(label ~ ., data=abalone, perc.over=2000,

perc.under=10)

人工的な正例を2000/100倍(=20 倍)増やす

負例の数を次式で調整する(正例の数+人工的な正例の数)×10/100(=0.1)

Page 24: 不均衡データのクラス分類

> idx <- sample(1:10, nrow(abalone.smote), replace=T)> pred <- rep(NA, nrow(abalone.smote))> # 10-fold クロスバリデーションの実行> for (i in 1:10) {+ is.test <- idx == i+ abalone.train <- abalone.smote[!is.test, ]+ abalone.test <- abalone.smote[is.test, -9]+ fit.ksvm <- ksvm(label ~., data=abalone.train, kernel="polydot", kpar=list(degree=2))+ pred[is.test] <- predict(fit.ksvm, abalone.test)+ }

Page 25: 不均衡データのクラス分類

> # SMOTEでの補間点も含むデータに対する分割表> table(abalone.smote$label, pred) negative positive negative 19 13 positive 1 351> # 元々のデータに対する分割表> is.original <- rownames(abalone.smote) %in% + rownames(abalone)> table(abalone.smote[is.original, "label"], + pred[is.original]) negative positive negative 19 13 positive 0 32

まだまだチューニングの余地はあるが,

それでも精度はかなり向上

Page 26: 不均衡データのクラス分類

Warning!!

SMOTE関数を使用する際は,

データのクラスラベルは

最後の列に配置しよう(SMOTE関数が使用している

smoote.exs関数の仕様)

thanks to @dichikaさん

Page 27: 不均衡データのクラス分類

またSMOTEがベストな選択とは

限らない

SMOTE以降も様々な手法が

提案されているGranular SVMなど

Page 28: 不均衡データのクラス分類

最後にランダムフォレストでの

不均衡データへの対処方法に

ついても少しだけ

Page 29: 不均衡データのクラス分類

ランダムフォレストの

提案者たちによると,

ランダムフォレストでの

不均衡データへの対応は2つ

Page 30: 不均衡データのクラス分類

Weighted Random Forest  正例,負例をそれぞれ誤って分類する際のペ

ナルティを以下の2箇所で考慮する. Gini係数を評価基準として決定木の枝を作成する

とき

予測ラベルを決定する際に重み付き多数決を取るとき

Balanced Random Forest各ツリーを構築する際, 正例のデータ数と同じだけ負例のデータをサンプリングして学習する.

Page 31: 不均衡データのクラス分類

RのrandomForestパッケージでは,

Weighted Random Forest  引数classwtが部分的に対応している模様

(Gini係数のみ?,古いfortranコードを用いている)

Balanced Random Forest  引数sampsizeに正例と負例に対して同じサ

ンプル数を指定する

Page 32: 不均衡データのクラス分類

引数classwtを調整してもあまり効果はない?

randomForestパッケージの管理者によると・・・(http://bit.ly/xJ2mUJ)

現在のclasswtオプションはパッケージが開発された当初から存在しているが,公式のfortranのコード(バージョン4以降)の実装とは異なる.クラスの重みを考慮するのは,ノード分割時にGini係数を算出する際のみである.

我々は,クラスの重みをGini係数の算出においてのみ用いても,極端に不均衡なデータ(例えば1:100やそれ以上)に対してはあまり役に立たないことが分かった.そこで,Breiman教授はクラスの重みを考慮する新しい方法を考案した.この方法は新しいfortranコードに実装されている.

現在のパッケージのclasswtにクラスの重みを指定しても,我々が望んでいた結果が過去に得られなかったことだけは付記しておく.

Page 33: 不均衡データのクラス分類

まとめ

不均衡データ="各クラスに属するサンプル数に偏りがあるデータ"

不均衡データに対するクラス分類においてはいろいろと工夫が必要な場合がある

対応方法としては,正例の誤判別ペナルティを調整する方法とサンプリングを工夫する方法が代表的

個々の問題に応じていろいろと試すべし

Page 34: 不均衡データのクラス分類

参考資料

Using Random Forest to Learn Imbalanced Data

Learning from the imbalanced data