MENU

R でリッジ回帰・ラッソ回帰・エラスティックネットを実行する方法

エラスティックネットを簡単に解説

R で実行する方法も解説

>>もう統計で悩むのは終わりにしませんか? 

↑期間・数量限定で無料プレゼント中!

目次

リッジ・ラッソ・エラスティックネットとは?

線形回帰モデルは、係数 β(パラメータ)を推定するときに最小二乗法を用いる。

通常の最小二乗法は、従属変数の実測値とモデルから計算された値との差=残差を二乗して足し合わせる。

この合計が最小になるパラメータのセットを見つける。

リッジ、ラッソ(LASSO)、エラスティックネットは残差の二乗和に以下の式を足したものを最小にする方法を取る。「罰則」と呼ぶ。

$$ \lambda \left( \frac{1 – \alpha}{2} || \beta ||_2^2 + \alpha || \beta ||_1 \right) $$

$$ = \lambda \sum_{j=1}^p \left( \frac{1 – \alpha}{2} \beta_j^2 + \alpha |\beta_j| \right) $$

リッジは最初の項だけ、ラッソは後の項だけ、エラスティックネットはどちらの項も使う方法だ。

α が0の時はリッジ、α が1の時はラッソ、0と1の間のときはエラスティックネットになる。

最初の項は$ \beta^2 $ の和になっている。

後の項は β の絶対値の和になっている。

いずれも β が多くなる、大きくなると、全体が大きくなる。

つまり、どんなに残差二乗和が小さくなるようにしても、この項たちが大きくなったのでは、目的が達成できない。

「罰則」と呼ばれるゆえんだ。

β を小さくする、いくつかを0にするなどして、「罰則」を小さくする。

結果として、当てはまりすぎ(過学習)を防ぐことになる。

ちなみに $ || \beta ||_2^2 $ とか、$ || \beta ||_1 $ はノルムと呼ばれる。

$$ || \beta ||_2^2 = \sqrt{| \beta |_1^2 + |\beta|_2^2 + \cdots + |\beta|_n^2} $$

$$ ||\beta||_1 = |\beta|_1 + |\beta|_2 + \cdots + |\beta|_n $$

リッジ・ラッソ・エラスティックネットの名前の由来

リッジ(Ridge)は、一般的な意味は盛り上がった場所、例えば山の背、尾根など。

二乗和の項を入れることで、上に凸型の二次反応関数に、数学的類似性があるところから名づけられた。

ラッソ(LASSO)は、Least Absolute Shrinkage and Selection Operator の頭文字語。

係数の絶対値(Absolute)を用いる方法で、係数を小さくして(Shrinkage)罰則を小さくし、要らない変数の係数をゼロにして変数を選択する(Selection)方法だ。

エラスティックネット(Elastic net)は、まるで伸縮性の投網のように「大きな魚(重要な係数)全部」を残すイメージからつけられた名前だ。

>>もう統計で悩むのは終わりにしませんか? 

↑1万人以上の医療従事者が購読中

エラスティックネットを R で実行するために必要なパッケージの準備

最初に一回インストール。

glmnetパッケージとISLRパッケージ。

install.packages("glmnet")
install.packages("ISLR")

ともに呼び出しておく。

library(glmnet)
library(ISLR)

エラスティックネットを R で行ってみる例題のデータを準備

ISLRパッケージ中のCollegeデータを使う。

米国の777大学の出願者や学生数、書籍購入にかかるコストなどという18個のプロファイルデータ。

学習データとテストデータに分ける。

5分の4を学習データ。5分の1をテストデータにする。

set.seed(20180921)
sub <- sample(1:777, round(777*4/5))

例題は、登録する学生数(Enroll)を予測するモデルを作ること。

エラスティックネットの前に従来の最小二乗法を実行してみる

Enrollをその他の変数全部で予測する回帰式を作る。

lm.res <- lm(Enroll ~ ., data=College[sub,])
summary(lm.res)

以下のように計算結果が表示される。

> summary(lm.res)
Call:
lm(formula = Enroll ~ ., data = College[sub, ])
Residuals:
Min       1Q   Median       3Q      Max
-1577.18   -63.47   -12.88    45.64  1581.09
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 219.946039  87.176801   2.523 0.011892 *
PrivateYes  -20.716365  29.254284  -0.708 0.479126
Apps         -0.040325   0.007908  -5.099 4.57e-07 ***
Accept        0.162698   0.014738  11.040  < 2e-16 ***
Top10perc     4.381100   1.270779   3.448 0.000605 ***
Top25perc    -2.206551   0.943228  -2.339 0.019642 *
F.Undergrad   0.142490   0.004467  31.901  < 2e-16 ***
P.Undergrad  -0.029804   0.008131  -3.666 0.000269 ***
Outstate     -0.004381   0.004120  -1.063 0.288023
Room.Board   -0.018011   0.010351  -1.740 0.082361 .
Books         0.018743   0.049424   0.379 0.704654
Personal     -0.004377   0.014736  -0.297 0.766533
PhD           0.353353   1.024941   0.345 0.730399
Terminal     -1.275895   1.139472  -1.120 0.263276
S.F.Ratio    -0.842953   2.686361  -0.314 0.753789
perc.alumni   1.920409   0.879343   2.184 0.029353 *
Expend        0.001368   0.002644   0.517 0.605075
Grad.Rate     0.277165   0.639241   0.434 0.664745
---
Signif. codes:  0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 199.2 on 604 degrees of freedom
Multiple R-squared:  0.9529,    Adjusted R-squared:  0.9516
F-statistic: 718.9 on 17 and 604 DF,  p-value: < 2.2e-16

モデルから得られる予測値と実測値のかい離を mean squared error of prediction (MSEP) で確認する。

mean((predict(lm.res)-College[sub,]$Enroll)^2)
> mean((predict(lm.res)-College[sub,]$Enroll)^2)
[1] 38530.83

学習データから得られたモデルをテストデータに適用して、テストデータで得られる予測値と実測値のかい離を MSEP で確認する。

lm.test <- predict(lm.res, newdata=College[-sub,])
mean((lm.test - College[-sub,]$Enroll)^2)
> mean((lm.test - College[-sub,]$Enroll)^2)
[1] 47213.26

MSEPはテストデータで大きくなった。

これは学習データでの予測モデルの性能があまり高くないことを示している。

リッジで解析した結果

glmnetパッケージのglmnet()を使う。

データは行列で与える。

data.matrix()を使う。

説明変数, 従属変数の順番に指定し、alpha=0を指定する。

ridge.res <- glmnet(data.matrix(College[sub,-4]), College[sub,]$Enroll, alpha=0)
mean((predict(ridge.res, newx=data.matrix(College[sub, -4]))-College[sub,]$Enroll)^2)
ridge.test <- predict(ridge.res, newx=data.matrix(College[-sub,-4]))
mean((ridge.test - College[-sub,]$Enroll)^2)

学習データで作られたモデルを、学習データとテストデータの MSEP で見てみると、テストデータでははるかに MSEP が大きくなっている。

あまり予測性能はよくない。

> mean((predict(ridge.res, newx=data.matrix(College[sub, -4]))-College[sub,]$Enroll)^2)
[1] 442744.8
> mean((ridge.test - College[-sub,]$Enroll)^2)
[1] 558366.1

予測性能を上げる方法として、クロスバリデーション(cross-validation)という方法がある。

学習データをさらに分割して、テストセット1つと学習セットとして繰り返し、最適な λ を見つける方法。

学習データにcross-validation付きのglmnetを適用して、結果をプロットする。

ridge.res.cv <- cv.glmnet(data.matrix(College[sub,-4]), College[sub,]$Enroll, alpha=0)
plot(ridge.res.cv)

MSEP(Y軸)が最も小さい値を確認する。

左側の縦破線が通っている赤いドットのY軸値。

> min(ridge.res.cv$cvm)
[1] 61345.74

MSEP が最も小さいときの λ と $\log (\lambda) $ を確認する(左側の縦破線のX軸値)。

> ridge.res.cv$lambda.min
[1] 95.77041
> log(ridge.res.cv$lambda.min)
[1] 4.561954

MSEP が最も小さいときの λに対応した回帰係数を確認する。

> coef(ridge.res.cv, s="lambda.min")
18 x 1 sparse Matrix of class "dgCMatrix"
1
(Intercept)  2.234662e+02
Private     -7.114514e+01
Apps         1.738649e-02
Accept       1.106883e-01
Top10perc    2.040518e+00
Top25perc   -3.542996e-01
F.Undergrad  1.035560e-01
P.Undergrad  8.384248e-03
Outstate    -4.248129e-03
Room.Board  -3.121038e-02
Books        2.823821e-02
Personal     1.564955e-02
PhD          5.052552e-01
Terminal     2.447818e-02
S.F.Ratio    2.254079e+00
perc.alumni  1.854235e+00
Expend      -2.158011e-04
Grad.Rate    1.225929e-01

学習データでMSEPが最も小さいときの λ のモデルをテストデータに適用する。

ridge.test.cv <- predict(ridge.res.cv, s="lambda.min", newx=data.matrix(College[-sub,-4]))
mean((ridge.test.cv-College[-sub,]$Enroll)^2)

テストデータの予測値と実測値のかい離を MSEP で求める。

> mean((ridge.test.cv-College[-sub,]$Enroll)^2)
[1] 44719.1

学習データの MSEP は、以下の通り。

> min(ridge.res.cv$cvm)
[1] 61345.74

テストデータの MSEP のほうが小さくなっているのがわかる。

予測性能がよいことを示している。

ラッソで解析した結果

glmnet()でalpha=1と指定する。

最初からクロスバリデーションを使う。

lasso.res.cv <- cv.glmnet(data.matrix(College[sub,-4]), College[sub,]$Enroll, alpha=1)
plot(lasso.res.cv)

MSEP が最小値を表示させる(Y軸)。

MSEP が最小値の $ \log (\lambda) $ を表示させる(X軸)。

MSEP 最小値の λ のときの回帰係数を表示させる。

> min(lasso.res.cv$cvm)
[1] 46512.83
> log(lasso.res.cv$lambda.min)
[1] -0.5781604
> coef(lasso.res.cv, s="lambda.min")
18 x 1 sparse Matrix of class "dgCMatrix"
1
(Intercept) 223.249334574
Private     -17.323492035
Apps         -0.034361012
Accept        0.152731795
Top10perc     3.758399461
Top25perc    -1.812982422
F.Undergrad   0.142965370
P.Undergrad  -0.029337386
Outstate     -0.003177355
Room.Board   -0.018717120
Books         0.012830680
Personal     -0.003259145
PhD           0.191660710
Terminal     -1.050251664
S.F.Ratio    -0.547854820
perc.alumni   1.834686143
Expend        0.001059255
Grad.Rate     0.177922346

学習データでもっともすぐれたモデルで、テストデータ予測をする。

MSEP を計算する。

lasso.test.cv <- predict(lasso.res.cv, s="lambda.min", newx=data.matrix(College[-sub,-4]))
mean((lasso.test.cv-College[-sub,]$Enroll)^2)
> mean((lasso.test.cv-College[-sub,]$Enroll)^2)
[1] 46711.87

学習データでの MSEP とほぼ同じ値。

以下が、学習データでの MSEP の値。

> min(lasso.res.cv$cvm)
[1] 46512.83

大きく増加しているわけではないので、予測に使えなくはない。

エラスティックネットの結果

0 < α< 1 がエラスティックネットだ。

リッジとラッソの中間で、いいとこどりの方法。

α を振って試してくれる関数が glmnetUtils パッケージの cva.glmnet() だ。

最初一回だけインストールする。

使うときはlibrary()で呼び出す。

install.packages("glmnetUtils")
library(glmnetUtils)

cva.glmnet() は cv.glmnet() と書き方は一緒。

α はデフォルトで11個に振ってくれる。

elnet.res.cv <- cva.glmnet(data.matrix(College[sub,-4]), College[sub,]$Enroll)
plot(elnet.res.cv)

$ \log (\lambda) $ とMSEPのプロットは以下の通り。

αが11個に振られているので、11本のグラフになる。

αを確認すると以下の通り。

> elnet.res.cv$alpha
[1] 0.000 0.001 0.008 0.027 0.064 0.125 0.216 0.343 0.512 0.729 1.000

最適な α を選ぶため MSEP がもっとも小さい α を探す。

各 α のうち最も小さい MSEP を取りだし、その中でもっとも小さいMSEPを取り出したところ、α = 1 がもっとも MSEP が小さかった。

つまり、ラッソがもっとも当てはまりがよいモデルであった。

> sapply(sapply(elnet.res.cv$modlist, "[[", "cvm"),min)
[1] 61274.57 61208.48 47948.64 47276.72 47268.60 47292.46 47324.64 47347.99 47177.38
[10] 47006.23 46913.66
> min(sapply(sapply(elnet.res.cv$modlist, "[[", "cvm"),min))
[1] 46913.66

α = 1 のときの、MSEP が最小になる λ のモデルを使って、テストデータで予測する。

elnet.test.cv <- predict(elnet.res.cv, alpha=1, s="lambda.min", newx=data.matrix(College[-sub,-4]))
mean((elnet.test.cv-College[-sub,]$Enroll)^2)

MSEP は学習データよりも小さくなり、予測性能が高いと言える。

> mean((elnet.test.cv-College[-sub,]$Enroll)^2)
[1] 45275.5

まとめ

学習データに当てはまりすぎない、予測性能に優れたモデルを作る、リッジ、ラッソ、エラスティックネットを紹介した。

リッジがいいか、ラッソがいいか、は、エラスティックで α を振ってみて、選ぶのがよい。

glmnetUtils パッケージの cva.glmnet() は痒いところに手が届く関数で使いやすい。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

リサーチクエスチョン探し?データ分析?論文投稿?、、、で、もう悩まない!

第1章臨床研究ではなぜ統計が必要なのか?計画することの重要性
  • 推定ってどんなことをしているの?
  • 臨床研究を計画するってどういうこと?
  • どうにかして標本平均を母平均に近づけられないか?
第2章:研究目的をどれだけ明確にできるのかが重要
  • データさえあれば解析でどうにかなる、という考え方は間違い
  • 何を明らかにしたいのか? という研究目的が重要
  • 研究目的は4種類に分けられる
  • 統計専門家に相談する上でも研究目的とPICOを明確化しておく
第3章:p値で結果が左右される時代は終わりました
  • アメリカ統計協会(ASA)のp値に関する声明で指摘されていること
  • そうは言っても、本当に有意差がなくてもいいの…?
  • なぜ統計専門家はp値を重要視していないのか
  • 有意差がない時に「有意な傾向があった」といってもいい?
  • 統計を放置してしまうと非常にまずい
第4章:多くの人が統計を苦手にする理由
  • 残念ながら、セミナー受講だけで統計は使えません。
  • インプットだけで統計が使えない理由
  • どうやったら統計の判断力が鍛えられるか?
  • 統計は手段なので正解がないため、最適解を判断する力が必要
第5章:統計を使えるようになるために今日から何をすれば良いか?
  • 論文を読んで統計が使えるようになるための5ステップ
第6章:統計を学ぶために重要な環境
  • 統計の3つの力をバランスよく構築する環境

以下のボタンをクリックして、画面に出てくる指示に従って、必要事項を記入してください。

この記事を書いた人

統計 ER ブログ執筆者

元疫学研究者

統計解析が趣味

コメント

コメントする

目次