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

L1正則化による変数選択

 今回は、glmnetパッケージを使って、L1正則化 (LASSO) による変数選択を行ってみます。分析データは、kernlabパッケージのspamデータセットとします。
 まずは、L1正則化によるspam/nonspamの2値判別を行います。*1

# パッケージの読み込み
library(glmnet)
library(kernlab)
# 分析データの読み込み
data(spam)
# L1正則化
set.seed(1)
spam.glmnet <- glmnet(as.matrix(spam[, -58]), spam[, 58], family = "binomial")
# 最適なlambdaの求解
set.seed(1)
spam.cv.glmnet <- cv.glmnet(as.matrix(spam[, -58]), spam[, 58], family = "binomial")
# 混同行列の表示
(spam.tab <- table(as.numeric(spam[, 58]), predict(spam.glmnet, as.matrix(spam[, -58]), s = spam.cv.glmnet$lambda.min, type = "class")))
# 判別精度の計算
sum(diag(spam.tab)) / sum(spam.tab)

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

# 混同行列
  nonspam spam
1    2670  118
2     191 1622
# 判別精度
[1] 0.9328407

 また、正則化パスを描画するには、以下のようにplot関数を使います。

# 正則化パスの描画
plot(spam.glmnet)

f:id:langstat:20141010201932p:plain

 そして、重要度の高い変数を表示するには、以下のような処理を行います。*2

# 重要度の高い変数をプロット
spam.variable.importance <- spam.glmnet$beta[, match(spam.cv.glmnet$lambda.min, spam.glmnet$lambda)]
dotchart(tail(sort(spam.variable.importance), 30), main = "variable importance")

f:id:langstat:20141010202223p:plain

 この図を見ると、charDollar、remove、num000、charHashという4つの変数が判別に大きく寄与していることが分かります。

*1:多値判別の場合は、glmnet関数とcv.glmnet関数の引数familyを"multinomial"とします。

*2:ここでは、重要度上位30位までをプロットしています。