バイオ・データ・マイニング/Rで回帰分析する のバックアップの現在との差分(No.1)


  • 追加された行はこの色です。
  • 削除された行はこの色です。
#freeze
*はじめに [#gc93c04a]

『Rによるバイオインフォマティクスデータ解析』の7.17節LASSOを参考にして,回帰分析をします.
ここでは、『Rによるバイオインフォマティクスデータ解析』の7.17節「LASSO」を参考にして、回帰分析をします。

#html{{
<iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=tohgoroh-22&o=9&p=8&l=as1&asins=4320057082&ref=tf_til&fc1=444B4C&IS2=1&lt1=_blank&m=amazon&lc1=444B4C&bc1=FFFFFF&bg1=FFFFFF&f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="https://rcm-fe.amazon-adsystem.com/e/cm?ref=tf_til&t=tohgorohmatsu-22&m=amazon&o=9&p=8&l=as1&IS2=1&detail=1&asins=4320057082&linkId=f6db5311dcfd9a82f5dee20859d39574&bc1=ffffff&lt1=_blank&fc1=444b4c&lc1=444b4c&bg1=ffffff&f=ifr"></iframe>
}}

LASSO回帰の前に,線形回帰と最小二乗法をやります.
きちんと理解するために、まずは単回帰と重回帰という2種類の線形回帰をやり、その後にLasso回帰とRidge回帰をやります。
その後、多項回帰と二項回帰をやります。


*準備 [#e708ecca]

まずは,標準で使用できるirisデータを使います.
Rのインストールについては、次のページを見てください。
-[[MacでRを使う>機械学習/MacでRを使う]]
-[[WindowsでRを使う>機械学習/WindowsでRを使う]]

このデータは,ユリの種類(Species)を花びらの長さ(Sepal.Length),幅(Lepal.Width),がくの長さ(Petal.Length),幅(Petal.Width)によって分類する問題です.
長さと幅は連続値,種類はsetosa, versicolor, virginicaのいずれかをとる離散値です.
最初は、標準で使用できる''irisデータセット''を使います。
#geshi(rsplus){{
data(iris)
}}

#geshi(sh){{
> data(iris)
> names(iris)
[1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"     
このデータセットは、アヤメの種類(Species)をがく片の長さ(Sepal.Length)、幅(Lepal.Width)、花びらの長さ(Petal.Length)、幅(Petal.Width)によって分類する問題です。
長さと幅は連続値、種類はsetosa, versicolor, virginicaのいずれかをとる離散値です。

このデータセットには、150個のデータが含まれています。
ランダムに10個のデータを選択して、見てみましょう。
#geshi(rsplus){{
iris[sort(sample(1:150,10)),]
}}
#geshi(rsplus){{
    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
4            4.6         3.1          1.5         0.2     setosa
22           5.1         3.7          1.5         0.4     setosa
65           5.6         2.9          3.6         1.3 versicolor
97           5.7         2.9          4.2         1.3 versicolor
100          5.7         2.8          4.1         1.3 versicolor
108          7.3         2.9          6.3         1.8  virginica
116          6.4         3.2          5.3         2.3  virginica
122          5.6         2.8          4.9         2.0  virginica
136          7.7         3.0          6.1         2.3  virginica
146          6.7         3.0          5.2         2.3  virginica
}}

ここでは,がくの長さ(Petal.Length)を被説明変数(目的変数)として,花びらの長さ(Sepal.Length)を説明変数としてモデルを学習します.

この関係をプロットすると次のようになります.

#geshi(sh){{
> plot(iris$Sepal.Length, iris$Petal.Length)
*線形回帰(単回帰) [#s1fe6159]

今から作るモデルによって説明したい変数を''目的変数''といい、目的変数を説明するために使う変数を''説明変数''と言います。
統計の分野では、目的変数を''従属変数''、説明変数を''独立変数''と呼びます。

まず、説明変数が1つの''単回帰''(single linear regression)を行います。
つまり、モデルが次のような式で表される直線をデータから求めます。
\[\hat{y} = \beta_0 + \beta_1 x_1\]
ここで、[math]\hat{y}[/math]がモデルによる''予測値''、[math]x_1[/math]が''説明変数''、[math]\beta_0[/math]が''定数項''、[math]\beta_1[/math]が([math]x_1[/math]の)''係数''です。

ある観測値 [math](x_i, y_i)[/math] に対して、モデルの予測値 [math]\hat{y_i}[/math] と観測値 [math]y_i[/math] の差を''残差''といい、次の式で表されます。
\[ y_i - \hat{y_i} = y_i - (\beta_0 + \beta_1 x_{i, 1}) \]

線形回帰では、''残差の二乗の和''を最小化するような係数と定数項を''最小二乗法''を使って求めます。
つまり、単回帰では、[math]N[/math] 個の観測データに対して、次の値を最小化するよう [math]\beta_0[/math]と [math]\beta_1[/math] を求めます。
(求め方の説明は省きます。)
\[ \sum_{i=1}^N \left(y_i - (\beta_0 + \beta_1 x_{i,1})\right)^2 \]

例として、がくの長さ(Petal.Length)を横軸、花びらの長さ(Sepal.Length)を縦軸にとって、150個のデータをプロットしてみます。
#geshi(rsplus){{
plot(iris$Sepal.Length, iris$Petal.Length)
}}
#ref(iris_single_rawdata.png,nolink,50%)

#ref(iris_rawdata.png);
どうやら、花びらの長さとがくの長さの間には正の相関(一方が大きいと他方も大きいという関係)がありそうですね。
そこで、花びらの長さ(Sepal.Length)を [math]x_1[/math](説明変数)、がくの長さ(Petal.Length)を [math]y[/math](目的変数)として、単回帰を行いましょう。

Rでは、モデルの式を、記号''~''を使って「目的変数 ~ 説明変数」というように表します。
したがって、目的変数 [math]y[/math] をがくの長さ(Petal.Length)、説明変数 [math]x_1[/math] を花びらの長さ(Sepal.Length)とするとき、モデルの式は「y ~ x1」となります。
#geshi(rsplus){{
y <- iris$Petal.Length
x1 <- iris$Sepal.Length
}}

線形回帰は、標準で用意されている''lm関数''にモデル式を入力して行います。
#geshi(rsplus){{
iris.sgl <- lm(y ~ x1)
}}

*最小二乗法 [#aac422ee]
学習された結果を表示してみると、次のようになります。
#geshi(rsplus){{
iris.sgl
}}
#geshi(rsplus){{

Call:
lm(formula = y ~ x1)

Coefficients:
(Intercept)           x1  
     -7.101        1.858  

}}
Coefficientsは係数を表し、Interceptは定数項の値(切片)を表します。
つまり、花びらの長さを [math]x_1[/math]、がくの長さを [math]y[/math] とすると、学習された式は次のように書けます。
\[ y =  -7.101 + 1.858 x_1 \]

学習された単回帰モデルを図示します。
#geshi(rsplus){{
plot(x1, y)
abline(iris.sgl)
}}
#ref(iris_single_model.png,nolink,50%)

*線形回帰 [#s1fe6159]
学習されたモデルを''summary関数''に渡すと、モデルに関する情報のサマリーが出力されます。
#geshi(rsplus){{
summary(iris.sgl)
}}
#geshi(rsplus){{

まずは,線形モデルによる回帰を行います.
Call:
lm(formula = y ~ x1)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.47747 -0.59072 -0.00668  0.60484  2.49512 

ここでは,線形回帰,LASSO回帰,Ridge回帰を行います.
Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -7.10144    0.50666  -14.02   <2e-16 ***
x1           1.85843    0.08586   21.65   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

LASSO回帰はglmnetパッケージに含まれています.
glmnetパッケージは
そこで,glmnetパッケージをインストールして,使用します.
Residual standard error: 0.8678 on 148 degrees of freedom
Multiple R-squared:   0.76,	Adjusted R-squared:  0.7583 
F-statistic: 468.6 on 1 and 148 DF,  p-value: < 2.2e-16
}}

#geshi(sh){{
> install.packages("glmnet")
> library(glmnet)
''Residuals''は、残差の最小値、中央値、最大値、四分位数を表します。

''Coefficients''は、''切片'' (Intercept)  [math]\beta_0[/math] と [math]x_1[/math] の''係数'' [math]\beta_1[/math] の''推定値'' (Estimate)、''標準誤差'' (Std. Error)を表します。

また、それぞれの推定値が 0 であるという帰無仮説に対するt検定の''t統計量'' (t value)、''p値'' (Pr(>|t|)) が示されています。
p値が0.05を超えている場合は、その説明変数は有意水準5%で統計的に有意ではなく、使えないと判断します。

''Multiple R-squared''は、''決定係数''で、このモデルがどのくらい説明できているかを 0 から 1 の範囲で表します。

単回帰では説明変数を1つしか使いませんが、説明変数を複数使うことができ、説明変数を増やすと決定係数を1に近づけることができてしまいます。
''Adjusted R-squared''は、''自由度調整済み決定係数''で、説明変数の数(自由度)によって調整した決定係数を表します。
説明変数の数が異なるモデルを比較するときには、自由度調整済み決定係数を使います。

最後に、係数が全て 0 であるという帰無仮説に対するF検定の''F統計量'' (F-statistic) と''p値'' (p-value) が示されています。
p値が0.05を超えている場合は、このモデルは有意水準5%で統計的に有意ではなく、使えないと判断します。


次に、予測誤差を視覚化するため、それぞれのデータについて、横軸に実際のがくの長さ(Petal.Length)、縦軸にその予測値をとってグラフを表示します。
予測値は''predict関数''で求めることができます。
#geshi(rsplus){{
plot(y, predict(iris.sgl))
abline(a=0,b=1)
}}
#ref(iris_single_errors.png,nolink,50%)

データは,標準で使えるiris,glmnet
この予測がどのくらい良いのかを表すために、''平均二乗誤差''(実際の値と予測値の差の二乗の平均)を求めます。
\[\textit{MSE} = \frac{1}{N}\sum_{i=1}^{N} \left(y_i - (\beta_0 + \beta_1 x_{i,1})\right)^2\]
#geshi(rsplus){{
mean((y - predict(iris.sgl))**2)
}}
#geshi(rsplus){{
[1] 0.743061
}}



*線形回帰(重回帰) [#bd685357]

説明変数が複数ある線形回帰を''重回帰''(multiple linear regression)といいます。

重回帰のモデルは次のような式で表されます。
\[y = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + \dots + \beta_p x_p\ = \beta_0 + \beta^\mathrm{T}\bf{x}\]
ここで、[math]\beta[/math]と[math]\bf{x}[/math]は、それぞれ[math]\beta_1, \dots, \beta_p[/math]と[math]x_1, \dots, x_p[/math]を要素とするベクトルです。

また、単回帰のときと同様に、次式で表される二乗誤差の総和を最小化するような[math]\beta_0, \dots, \beta_p[/math]を求めます。
\[\sum_{i=1}^N \left(y_i - (\beta_0 + \beta^\mathrm{T}\bf{x}_i)\right)^2\]

ここでは、がくの長さ(Petal.Length)を目的変数 [math]y[/math]、花びらの長さ(Sepal.Length)、幅(Sepal.Width)、がくの幅(Petal.Width)を説明変数 [math]x_1[/math], [math]x_2[/math], [math]x_3[/math] として重回帰を行いましょう。
#geshi(rsplus){{
y <- iris$Petal.Length
x1 <- iris$Sepal.Length
x2 <- iris$Sepal.Width
x3 <- iris$Petal.Width
}}

説明変数が複数あるときは、モデルを表すときにそれぞれの変数を記号''+''で連結して表します。
ここでは、「y ~ x1+x2+x3」となります。

単回帰と同じように、''lm関数''を用いてモデルを学習します。
#geshi(rsplus){{
iris.mult <- lm(y ~ x1+x2+x3)
iris.mult$coefficients
}}
#geshi(rsplus){{
(Intercept)          x1          x2          x3 
 -0.2627112   0.7291384  -0.6460124   1.4467934 
}}
単回帰と同じように、学習された式は次のように書けます。
\[ y = -0.2627112 + 0.7291384 x_1 - 0.6460124 x_2 + 1.4467934 x_3 \]

単回帰と同じように、学習されたモデルを''summary関数''に渡すと、モデルに関する情報のサマリーが出力されます。
#geshi(rsplus){{
summary(iris.mult)
}}
#geshi(rsplus){{

Call:
lm(formula = y ~ x1 + x2 + x3)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.99333 -0.17656 -0.01004  0.18558  1.06909 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.26271    0.29741  -0.883    0.379    
x1           0.72914    0.05832  12.502   <2e-16 ***
x2          -0.64601    0.06850  -9.431   <2e-16 ***
x3           1.44679    0.06761  21.399   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.319 on 146 degrees of freedom
Multiple R-squared:  0.968,	Adjusted R-squared:  0.9674 
F-statistic:  1473 on 3 and 146 DF,  p-value: < 2.2e-16
}}


重回帰分析の場合はモデルが視覚化しにくいので、予測誤差だけ視覚化します。
#geshi(rsplus){{
plot(y, predict(iris.mult))
abline(a=0,b=1)
}}
#ref(iris_multiple_errors.png,nolink,50%)

単回帰と同様に、平均二乗誤差を求めます。
\[\textit{MSE} = \frac{1}{N} \sum_{i=1}^N (y_i - (\beta_0 + \beta^\mathrm{T}\bf{x}_i))^2\]
#geshi(rsplus){{
mean((y - predict(iris.mult))**2)
}}
#geshi(rsplus){{
[1] 0.09901965
}}
単回帰の場合よりも誤差がかなり小さくなっていることがわかります。



*Lasso回帰 [#p3d71085]

''Lasso回帰''(Lasso regression)は、モデル式は重回帰と同じですが、最小化する目的関数が次のような形をしています。
\[\sum_{i=1}^N \left( y_i - (\beta_0 + \beta^\mathrm{T}\bf{x}_i) \right)^2 + \lambda ||\beta||_1\]
ここで、[math]\lambda|\beta|[/math]を''正則化項''といい、[math]\lambda[/math]を''正則化パラメーター''といいます。

Lasso回帰の正則化に用いられている[math]||\beta||_1[/math]を''L1ノルム''といい、次のように計算します。
\[||\beta||_1 = \sum_{i=1}^p|\beta_i|\]
つまり、L1ノルムは係数の絶対値の和を表します。
正則化パラメーター[math]\lambda[/math]の値が大きいほど0に近い係数を好むようになります。


Lasso回帰は''glmnetパッケージ''((Friedman, Hastie, and Tibshirani: Regularization Paths for Generalized Linear Models via Coordinate Descent, Journal of Statistical Software, Vol. 33, No. 1, 2010.))に含まれています。
そこで、glmnetパッケージをインストールして、使用します。
#geshi(rsplus){{
install.packages("glmnet")
library(glmnet)
}}

Lasso回帰を行うには、glmnetパッケージの''glmnet関数''を用います。
引数には、説明変数行列と目的変数(そしてオプション)を与えます。
#geshi(rsplus){{
x <- cbind(x1, x2, x3)
iris.lasso <- glmnet(x, y)
}}
cbind関数は、列 (column) で結合するもので、x1, x2, x3 のそれぞれを列とした行列を作っています。

plot関数を使うと、正則化項の大きさとそれぞれの係数の関係をプロットすることができます。
#geshi(rsplus){{
plot(iris.lasso)
}}
#ref(iris_lasso_regularization.png,nolink,50%)
黒色の折れ線が花びらの長さ(Sepal.Length)、赤色の折れ線が花びらの幅(Sepal.Width)、緑色の折れ線ががくの幅(Petal.Width)を表しています。

縦軸はそれぞれの係数を表しています。
横軸の左端が最も正則化が強いとき、つまり、係数へのペナルティを最も大きくしたときであり、右端が最も正則化が弱いとき、つまり、係数に対するペナルティがないときです。

最も正則化が最も強いときは、すべての係数が0になっています。
そこから正則化を弱めていくと、緑色の線が表すがくの幅(Petal.Width)の係数だけが大きくなっていきます。
その後、他の係数も0ではなくなり、正則化項が0、つまりペナルティなしのときに重回帰のときと同じ係数になっています。

次に、最適な正則化パラメーター([math]\lambda[/math])の値を''交差検定''(''クロス・バリデーション'')を用いて求めます。
#geshi(rsplus){{
iris.lasso.cv = cv.glmnet(x, y)
}}

plotを用いて、[math]\lambda[/math]と平均二乗誤差の関係を表示すると次のようになります。
#geshi(rsplus){{
plot(iris.lasso.cv)
}}
#ref(iris_lasso_lambda.png,nolink,50%)
今回の例では正則化パラメーターの値が小さいほうが平均二乗誤差が小さくなりましたが、いつもこうなるわけではありません。

最も予測誤差が小さかったときの[math]\lambda[/math]の値は、クロス・バリデーションによって得られたオブジェクトの変数lambda.minに格納されています。
#geshi(rsplus){{
iris.lasso.cv$lambda.min
}}
#geshi(rsplus){{
[1] 0.008431423
}}

係数は変数betaに、定数項の値は変数a0に格納されています。
しかし、各[math]\lambda[/math]ごとの係数が格納された行列やベクトルになっていますので、which関数を用いて交差検定の予測誤差が最も小さかったときの[math]\lambda[/math]のインデックスを調べ、そのときの係数と定数項の値だけを表示します。
#geshi(rsplus){{
iris.lasso$beta[,which(iris.lasso$lambda==iris.lasso.cv$lambda.min)]
}}
#geshi(rsplus){{
Sepal.Length  Sepal.Width  Petal.Width 
   0.7171234   -0.6267432    1.4504055  
}}
#geshi(rsplus){{
iris.lasso$a0[which(iris.lasso$lambda==iris.lasso.cv$lambda.min)]
}}
#geshi(rsplus){{
       s57 
-0.2557475 
}}
重回帰と同様に表すと、学習された式を次のように書くことができます。
\[y = -0.2557475 + 0.7171234 x_1 - 0.6267432 x_ 2 + 1.4504055 x_3\]

単回帰、重回帰のときと同じように、平均二乗誤差を求め、予測誤差を視覚化します。
#geshi(rsplus){{
mean((y - predict(iris.lasso, x, s=iris.lasso.cv$lambda.min))**2)
}}
#geshi(rsplus){{
[1] 0.09915377
}}
#geshi(rsplus){{
plot(y, predict(iris.lasso, x, s=iris.lasso.cv$lambda.min))
abline(a=0,b=1)
}}
#ref(iris_lasso_errors.png,nolink,50%)




*Ridge回帰 [#wa18ca12]

''Ridge回帰''は、目的関数の正則化項が[math]\frac{\lambda}{2}||\beta||_2^2[/math]となっている回帰です。
つまり、Ridge回帰の目的関数は次のような形をしています。
\[\sum_{i=1}^N \left( y_i - (\beta_0 + \beta^\mathrm{T}\bf{x}_i) \right)^2 + \frac{\lambda}{2} ||\beta||_2^2\]

Ridge回帰の正則化に用いられている[math]||\beta||_2^2[/math]を''L2ノルム''といい、次のように計算します。
\[||\beta||_2^2 = \sum_{i=1}^p \beta_i^2\]

Lasso回帰では正則化項のペナルティが係数の絶対値に比例して増加しましたが、Ridge回帰では係数の2乗に比例して増加します。


Ridge回帰を行うには、''glmnet関数''で学習する際にオプションで''alpha=0''を指定します。
#geshi(rsplus){{
iris.ridge <- glmnet(x, y, alpha=0)
}}
後はLasso回帰のときと同じです。

まず、正則化項の大きさと係数の関係を表示します。
#geshi(rsplus){{
plot(iris.ridge)
}}
#ref(iris_ridge_regularization.png,nolink,50%)
Lasso回帰のグラフと比べると、Lasso回帰の方が係数を0にする傾向が強いことがわかります。

次に、クロス・バリデーションによって最適な[math]\lambda[/math]を求め、そのときの係数と定数項を表示します。
#geshi(rsplus){{
iris.ridge.cv <- cv.glmnet(x, y, alpha=0)
iris.ridge.cv$lambda.min
}}
#geshi(rsplus){{
[1] 0.1694069
}}
#geshi(rsplus){{
iris.ridge$beta[,which(iris.ridge$lambda==iris.ridge.cv$lambda.min)]
}}
#geshi(rsplus){{
Sepal.Length  Sepal.Width  Petal.Width 
   0.7882905   -0.6838069    1.2645594 
}}
#geshi(rsplus){{
iris.ridge$a0[which(iris.ridge$lambda==iris.ridge.cv$lambda.min)]
}}
#geshi(rsplus){{
       s99 
-0.2742464 
}}
これまでと同様に表すと、学習された式は次のように書けます。
\[y = -0.2742464 + 0.7882905 x_1 - 0.6838069 x_2 + 1.2645594 x_3\]

最後に、平均二乗誤差を求め、予測誤差をプロットします。
#geshi(rsplus){{
mean((y - predict(iris.ridge, x, s=iris.ridge.cv$lambda.min))**2)
}}
#geshi(rsplus){{
[1] 0.1083066
}}
#geshi(rsplus){{
plot(y, x, s=iris.ridge.cv$lambda.min))
abline(a=0,b=1)
}}
#ref(iris_ridge_errors.png,nolink,50%)

ちなみに、Lasso回帰のときと同じように[math]\lambda[/math]と平均二乗誤差の関係をプロットしようとしましたが、できませんでした。
#geshi(rsplus){{
plot(iris.ridge.cv)
}}
#geshi(rsplus){{
 以下にエラー axis(side = 3, at = sign.lambda * log(cvobj$lambda), labels = paste(cvobj$nz),  : 
   'at' と 'label' の長さが違います。 100 != 300 
}}


*多項回帰 [#wd1c3279]

irisデータのように目的変数(Species)の値が離散値(カテゴリー)のときは、''多項回帰''(Multinomial regression)を用います。

多項回帰を行うには、''glmnet関数''で学習する際にオプションで''family="multinomial"''を指定します。
#geshi(rsplus){{
x1 <- iris$Sepal.Length
x2 <- iris$Sepal.Width
x3 <- iris$Petal.Length
x4 <- iris$Petal.Width
x <- cbind(x1, x2, x3, x4)
y <- iris$Species
iris.mnorm <- glmnet(x, y, family="multinomial")
plot(iris.mnorm)
}}
#ref(iris_multinomial_regularization.png,nolink,50%)

それから、クロス・バリデーションを用いて最適な[math]\lambda[/math]を求めます。
#geshi(rsplus){{
iris.mnorm.cv <- cv.glmnet(x, y, family="multinomial")
plot(iris.mnorm.cv)
}}
#ref(iris_multinomial_lambda.png,nolink,50%)
今回は[math]\lambda[/math]が小さすぎても大きすぎてもダメです。

最後に、予測結果を''table関数''を用いて表にします。
目的変数が離散値なので、''predict関数''にオプション''type="class"''を指定します。
#geshi(rsplus){{
table(y, predict(iris.mnorm, x, s=iris.mnorm.cv$lambda.min, type="class"))
}}
#geshi(rsplus){{
            
             setosa versicolor virginica
  setosa         50          0         0
  versicolor      0         48         2
  virginica       0          1        49
}}
setosaは50個全て正しく分類できていますが、versicolorのうち2つをvirginicaと誤って分類し、virginicaの1つをversicolorと誤って分類しています。




*二項回帰 [#o625f55c]

目的変数の値が「はい」「いいえ」や「陽性」「陰性」など2種類の離散値(カテゴリー)のときは、''二項回帰''(binomial regression)を用います。

irisデータには、目的変数(Species)の値がsetosa、versicolor、virginicaであるデータが50個ずつ含まれていますから、ここからsetosaとversicolorだけを取り出して新しいデータ・フレームを作成し、二項回帰をやってみます。

まず、''subset関数''を用いてirisからSpeciesの値がsetosaかversicolorであるデータだけを取り出します。
また、''factor関数''を用いてSpciesのレベルを再定義します。
#geshi(rsplus){{
iris2 <- subset(iris, Species=="setosa" | Species=="versicolor")
iris2$Species <- factor(iris2$Species, level=c("setosa","versicolor"))
x1 <- iris2$Sepal.Length
x2 <- iris2$Sepal.Width
x3 <- iris2$Petal.Length
x4 <- iris2$Petal.Width
x <- cbind(x1, x2, x3, x4)
y <- iris2$Species
}}

二項回帰を行うには、''glmnet関数''で学習する際にオプションで''family="binomial"''を指定します。
後は多項回帰と同じです。
#geshi(rsplus){{
iris.binorm <- glmnet(x, y, family="binomial")
plot(iris.binorm)
}}
#ref(iris_binomial_regularization.png,nolink,50%)
#geshi(rsplus){{
iris.binorm.cv <- cv.glmnet(x, y, family="binomial")
plot(iris.binorm.cv)
}}
#ref(iris_binomial_lambda.png,nolink,50%)
#geshi(rsplus){{
table(y, predict(iris.binorm, x, s=iris.binorm.cv$lambda.min, type="class"))
}}
#geshi(rsplus){{
            
             setosa versicolor
  setosa         50          0
  versicolor      0         50
}}
こちらは全て正しく分類できました。



*糖尿病データへの応用 [#cac50579]

それでは、''diabetesデータ''に応用してみましょう。

このデータは''larsパッケージ''((Efron, Hastie,  Johnstone, and Tibshirani: Least Angle Regression, The Annals of Statistics, Vol. 32, No. 2, pp. 407–499, 2004.))に含まれていますので、まずはlarsパッケージをインストールします。
#geshi(rsplus){{
install.packages("lars")
library(lars)
data(diabetes)
}}

diabetesデータには、442人の糖尿病患者から観測された年齢、性別、BMI、平均血圧、6種類の血清測定値から成る10次元の説明変数行列xと1年後の糖尿病の進行度を表す目的変数ベクトルyが格納されています。

まず、重回帰を行い、平均二乗誤差を求めます。
#geshi(rsplus){{
x <- diabetes$x
y <- diabetes$y
diabetes.mult <- lm(y ~ x)
mean ((y - predict(diabetes.mult))**2)
}}
#geshi(rsplus){{
[1] 2859.69
}}


次に、Lasso回帰を行い、正則化項と係数の関係をプロットします。
#geshi(rsplus){{
diabetes.lasso <- glmnet(x, y)
plot(diabetes.lasso)
}}
#ref(diabetes_lasso_regularization.png,nolink,50%)
正則化が弱いときは(つまり、グラフの右の方では)、irisに比べて係数がかなり大きいことがわかります。

クロス・バリデーションでLasso回帰の最適な[math]\lambda[/math]を求めます。
#geshi(rsplus){{
diabetes.lasso.cv <- cv.glmnet(x, y)
diabetes.lasso.cv$lambda.min
}}
#geshi(rsplus){{
[1] 0.0735996
}}
#geshi(rsplus){{
plot(diabetes.lasso.cv)
}}
#ref(diabetes_lasso_lambda.png,nolink,50%)

Lasso回帰の平均二乗誤差を求めます。
#geshi(rsplus){{
mean((y - predict(diabetes.lasso, x, s=diabetes.lasso.cv$lambda.min))**2)
}}
#geshi(rsplus){{
[1] 2886.087
}}

最後に、Ridge回帰を行います。
#geshi(rsplus){{
diabetes.ridge <- x, y, alpha=0)
plot(diabetes.ridge)
}}
#ref(diabetes_ridge_regularization.png,nolink,50%)

クロス・バリデーションによってRidge回帰の最適な[math]\lambda[/math]を求めます。
#geshi(rsplus){{
diabetes.ridge.cv <- cv.glmnet(x, y, alpha=0)
diabetes.ridge.cv$lambda.min
}}
#geshi(rsplus){{
[1] 4.516003
}}

Ridge回帰の平均二乗誤差を求めます。
#geshi(rsplus){{
mean((y - predict(diabetes.ridge, x, s=diabetes.ridge.cv$lambda.min))**2)
}}
#geshi(rsplus){{
[1] 2881.332
}}



*構造活性相関データへの応用 [#e9570b3e]

いよいよ、『Rによるバイオインフォマティクスデータ解析』の7.17節で用いられている構造活性相関のデータである''dhfrデータセット''を対象に回帰を行います。

このデータセットは、''caretパッケージ''((Hothorn, Leisch, Hornik, and Zeileis: The design and analysis of benchmark experiments, Journal of Computational and Graphical Statistics, Vol. 14, pp. 675-699, 2005.))に含まれていますので、インストールしてから使用します。
#geshi(rsplus){{
install.package("caret")
library(caret)
data(dhfr)
}}

dhfrデータセットの中を調べてみます。
#geshi(rsplus){{
dim(dhfr)
}}
#geshi(rsplus){{
[1] 325 229
}}
#geshi(rsplus){{
names(dhfr)
}}
#geshi(rsplus){{
  [1] "Y"                    "moeGao_Abra_L"        "moeGao_Abra_R"       
  [4] "moeGao_Abra_acidity"  "moeGao_Abra_basicity" "moeGao_Abra_pi"      
  [7] "moe2D_BCUT_PEOE_0"    "moe2D_BCUT_PEOE_1"    "moe2D_BCUT_PEOE_2"   
 [10] "moe2D_BCUT_PEOE_3"    "moe2D_BCUT_SLOGP_0"   "moe2D_BCUT_SLOGP_1"  
 [13] "moe2D_BCUT_SLOGP_2"   "moe2D_BCUT_SLOGP_3"   "moe2D_BCUT_SMR_0"    
 [16] "moe2D_BCUT_SMR_1"     "moe2D_BCUT_SMR_2"     "moe2D_BCUT_SMR_3"    
 [19] "moe2D_FCharge"        "moe2D_GCUT_PEOE_0"    "moe2D_GCUT_PEOE_1"   
 [22] "moe2D_GCUT_PEOE_2"    "moe2D_GCUT_PEOE_3"    "moe2D_GCUT_SLOGP_0"  
 [25] "moe2D_GCUT_SLOGP_1"   "moe2D_GCUT_SLOGP_2"   "moe2D_GCUT_SLOGP_3"  
 [28] "moe2D_GCUT_SMR_0"     "moe2D_GCUT_SMR_1"     "moe2D_GCUT_SMR_2"    
 [31] "moe2D_GCUT_SMR_3"     "moe2D_Kier1"          "moe2D_Kier2"         
 [34] "moe2D_Kier3"          "moe2D_KierA1"         "moe2D_KierA2"        
 [37] "moe2D_KierA3"         "moe2D_KierFlex"       "moe2D_PEOE_PC."      
 [40] "moe2D_PEOE_PC..1"     "moe2D_PEOE_RPC."      "moe2D_PEOE_RPC..1"   
 [43] "moe2D_PEOE_VSA.0"     "moe2D_PEOE_VSA.1"     "moe2D_PEOE_VSA.2"    
 [46] "moe2D_PEOE_VSA.3"     "moe2D_PEOE_VSA.4"     "moe2D_PEOE_VSA.5"    
 [49] "moe2D_PEOE_VSA.6"     "moe2D_PEOE_VSA.0.1"   "moe2D_PEOE_VSA.1.1"  
 [52] "moe2D_PEOE_VSA.2.1"   "moe2D_PEOE_VSA.3.1"   "moe2D_PEOE_VSA.4.1"  
 [55] "moe2D_PEOE_VSA.5.1"   "moe2D_PEOE_VSA.6.1"   "moe2D_PEOE_VSA_FHYD" 
 [58] "moe2D_PEOE_VSA_FNEG"  "moe2D_PEOE_VSA_FPNEG" "moe2D_PEOE_VSA_FPOL" 
 [61] "moe2D_PEOE_VSA_FPOS"  "moe2D_PEOE_VSA_FPPOS" "moe2D_PEOE_VSA_HYD"  
 [64] "moe2D_PEOE_VSA_NEG"   "moe2D_PEOE_VSA_PNEG"  "moe2D_PEOE_VSA_POL"  
 [67] "moe2D_PEOE_VSA_POS"   "moe2D_PEOE_VSA_PPOS"  "moe2D_Q_PC."         
 [70] "moe2D_Q_PC..1"        "moe2D_Q_RPC."         "moe2D_Q_RPC..1"      
 [73] "moe2D_Q_VSA_FHYD"     "moe2D_Q_VSA_FNEG"     "moe2D_Q_VSA_FPNEG"   
 [76] "moe2D_Q_VSA_FPOL"     "moe2D_Q_VSA_FPOS"     "moe2D_Q_VSA_FPPOS"   
 [79] "moe2D_Q_VSA_HYD"      "moe2D_Q_VSA_NEG"      "moe2D_Q_VSA_PNEG"    
 [82] "moe2D_Q_VSA_POL"      "moe2D_Q_VSA_POS"      "moe2D_Q_VSA_PPOS"    
 [85] "moe2D_SMR"            "moe2D_SMR_VSA0"       "moe2D_SMR_VSA1"      
 [88] "moe2D_SMR_VSA2"       "moe2D_SMR_VSA3"       "moe2D_SMR_VSA4"      
 [91] "moe2D_SMR_VSA5"       "moe2D_SMR_VSA6"       "moe2D_SMR_VSA7"      
 [94] "moe2D_SlogP"          "moe2D_SlogP_VSA0"     "moe2D_SlogP_VSA1"    
 [97] "moe2D_SlogP_VSA2"     "moe2D_SlogP_VSA3"     "moe2D_SlogP_VSA4"    
[100] "moe2D_SlogP_VSA5"     "moe2D_SlogP_VSA6"     "moe2D_SlogP_VSA7"    
[103] "moe2D_SlogP_VSA8"     "moe2D_SlogP_VSA9"     "moe2D_TPSA"          
[106] "moe2D_VAdjEq"         "moe2D_VAdjMa"         "moe2D_VDistEq"       
[109] "moe2D_VDistMa"        "moe2D_Weight"         "moe2D_a_IC"          
[112] "moe2D_a_ICM"          "moe2D_a_acc"          "moe2D_a_aro"         
[115] "moe2D_a_base"         "moe2D_a_count"        "moe2D_a_don"         
[118] "moe2D_a_heavy"        "moe2D_a_hyd"          "moe2D_a_nBr"         
[121] "moe2D_a_nC"           "moe2D_a_nCl"          "moe2D_a_nF"          
[124] "moe2D_a_nH"           "moe2D_a_nN"           "moe2D_a_nO"          
[127] "moe2D_a_nS"           "moe2D_apol"           "moe2D_b_1rotN"       
[130] "moe2D_b_1rotR"        "moe2D_b_ar"           "moe2D_b_count"       
[133] "moe2D_b_double"       "moe2D_b_heavy"        "moe2D_b_rotN"        
[136] "moe2D_b_rotR"         "moe2D_b_single"       "moe2D_b_triple"      
[139] "moe2D_balabanJ"       "moe2D_bpol"           "moe2D_chi0"          
[142] "moe2D_chi0_C"         "moe2D_chi0v"          "moe2D_chi0v_C"       
[145] "moe2D_chi1"           "moe2D_chi1_C"         "moe2D_chi1v"         
[148] "moe2D_chi1v_C"        "moeGao_chi2_C"        "moeGao_chi2v_C"      
[151] "moeGao_chi3c"         "moeGao_chi3c_C"       "moeGao_chi3cv"       
[154] "moeGao_chi3cv_C"      "moeGao_chi3p"         "moeGao_chi3p_C"      
[157] "moeGao_chi3pv"        "moeGao_chi3pv_C"      "moeGao_chi4c"        
[160] "moeGao_chi4c_C"       "moeGao_chi4ca"        "moeGao_chi4ca_C"     
[163] "moeGao_chi4cav"       "moeGao_chi4cav_C"     "moeGao_chi4cv"       
[166] "moeGao_chi4cv_C"      "moeGao_chi4pc"        "moeGao_chi4pc_C"     
[169] "moeGao_chi4pcv"       "moeGao_chi4pcv_C"     "moe2D_chiral"        
[172] "moe2D_density"        "moe2D_diameter"       "moe2D_kS_aaCH"       
[175] "moe2D_kS_aaN"         "moe2D_kS_aaNH"        "moe2D_kS_aaO"        
[178] "moe2D_kS_aaS"         "moe2D_kS_aaaC"        "moe2D_kS_aasC"       
[181] "moe2D_kS_aasN"        "moe2D_kS_dO"          "moe2D_kS_ddsN"       
[184] "moe2D_kS_ddssS"       "moe2D_kS_dsCH"        "moe2D_kS_dsN"        
[187] "moe2D_kS_dssC"        "moe2D_kS_sBr"         "moe2D_kS_sCH3"       
[190] "moe2D_kS_sCl"         "moe2D_kS_sF"          "moe2D_kS_sNH2"       
[193] "moe2D_kS_sOH"         "moe2D_kS_ssCH2"       "moe2D_kS_ssNH"       
[196] "moe2D_kS_ssO"         "moe2D_kS_ssS"         "moe2D_kS_sssCH"      
[199] "moe2D_kS_sssN"        "moe2D_kS_ssssC"       "moe2D_kS_tCH"        
[202] "moe2D_kS_tsC"         "moe2D_lip_acc"        "moe2D_lip_don"       
[205] "moe2D_lip_druglike"   "moe2D_lip_violation"  "moe2D_logP.o.w."     
[208] "moe2D_logS"           "moe2D_mr"             "moe2D_opr_brigid"    
[211] "moe2D_opr_leadlike"   "moe2D_opr_nring"      "moe2D_opr_nrot"      
[214] "moe2D_opr_violation"  "moe2D_petitjean"      "moe2D_petitjeanSC"   
[217] "moe2D_radius"         "moe2D_rings"          "moe2D_vdw_area"      
[220] "moe2D_vdw_vol"        "moe2D_vsa_acc"        "moe2D_vsa_base"      
[223] "moe2D_vsa_don"        "moe2D_vsa_hyd"        "moe2D_vsa_other"     
[226] "moe2D_vsa_pol"        "moe2D_weinerPath"     "moe2D_weinerPol"     
[229] "moe2D_zagreb"
}}
#geshi(rsplus){{
levels(dhfr$Y)
}}
#geshi(rsplus){{
[1] "active"   "inactive"
}}
事例数が325、属性数が229です。
1個目の属性Yが目的変数で、あとの228個はすべて説明変数です。
これまでの例に比べると、説明変数がすごく多いですね。
Y、つまり目的変数の値はactiveとinactiveの2種類です。


目的変数の値が2種類のカテゴリーなので、二項回帰を行います。
#geshi(rsplus){{
dhfr.x <- as.matrix(dhfr[,-1])
dhfr.y <- dhfr[,1]
dhfr.binorm <- glmnet(dhfr.x, dhfr.y, family="binomial")
plot(dhfr.binorm)
}}
#ref(dhfr_binomial_regularization.png,nolink,50%)
説明変数の数が多いので、たくさんの線が描かれています。
意味はこれまでと同じで、一番左が最も大きく正則化して係数を小さくしたとき、一番右が正則化をまったく行っていないときです。

次に、クロス・バリデーションで最適な[math]\lambda[/math]を求めます。
#geshi(rsplus){{
dhfr.binorm.cv <- cv.glmnet(dhfr.x, dhfr.y, family="binomial")
plot(dhfr.binorm.cv)
}}
#ref(dhfr_binomial_lambda.png,nolink,50%)

最後に、精度を求めます。
#geshi(rsplus){{
(result <- table(dhfr.y, predict(lasso, dhfr.x, s=dhfr.binorm.cv$lambda.min, type="class")))
}}
#geshi(rsplus){{
          
           active inactive
  active      198        5
  inactive      6      116
(result[1,1] + result[2,2]) / (result[1,1] + result[1,2] + result[2,1] + result[2,2])
[1] 0.9661538
}}
96.6%の正解率でした。





*まとめ [#o5e18fce]

線形回帰のモデルは次のような式で表されます。
\[y = \beta_0 + \beta^\mathrm{T}\bf{x}\]
ここで、[math]\beta[/math] と [math]\bf{x}[/math] は、それぞれ [math]\beta_1, \dots, \beta_p[/math] と [math]x_1, \dots, x_p[/math] を要素とするベクトルです。
次元数が [math]p=1[/math] のときを単回帰、[math]p>1[/math] のときを重回帰といいます。

線形回帰では、二乗誤差の総和 [math]L(\beta, \bf{x})[/math] を最小化するような [math]\beta[/math] を求めます。
\[L(\beta, \bf{x}) = \sum_{i=1}^N \left(y_i - (\beta_0 + \beta^\mathrm{T}\bf{x}_i)\right)^2\]


Lasso回帰やRidge回帰では、損失関数 [math]L(\beta, \bf{x})[/math] に正則化項 [math]\lambda P(\beta)[/math] を加えたもの最小化するような [math]\beta[/math] を求めます。
\[L(\beta, \bf{x}) + \lambda \textit{P}(\beta)\]

ここで、[math]\lambda[/math] は正則化の強さを決めるパラメーターです。
[math]\lambda=0[/math] のとき、正則化項が [math]0[/math] になり、正則化なしの重回帰になります。
また、[math]\lambda=0[/math] かつ [math]p=1[/math](次元数が1)のとき、正則化なしの単回帰になります。
glmnet関数では、[math]\lambda[/math] の値をオプションsに設定します。

glmnet関数の正則化項 [math]P(\beta)[/math] は、次のような一般的な形をしています。
\[P(\beta) = (1 - \alpha)\frac{1}{2} ||\beta||_2^2 + \alpha ||\beta||_1\]

[math]\alpha[/math] は正則化の形を決めるパラメーターです。
[math]\alpha=1[/math] のときにLasso回帰、[math]\alpha=0[/math] のときにRidge回帰になります。
glmnet関数では、この [math]\alpha[/math] の値をオプションalphaに設定します。
デフォルトではalpha=1なので、alphaオプションを指定しないときはLasso回帰になります。
alpha=0と指定するとRidge回帰になります。
alphaの値を0と1の間に設定することもできます。

今回は、線形回帰の誤差関数に正則化項を加えたLasso回帰とRidge回帰をやりましたが、ロジスティック回帰、多項式回帰、ポアソン回帰、Cox回帰の誤差関数に正則化項を加えたLasso回帰やRidge回帰もできます。
また、多項回帰と二項回帰では、特に説明せずにデフォルトのLasso回帰を用いましたが、Ridge回帰を用いた多項回帰や二項回帰もできます。

回帰分析についてもっと詳しく知りたい場合は、参考文献に上げた『The Elements of Statistical Learning』を読むといいでしょう。
glmnet関数でロジスティック回帰、多項式回帰、ポアソン回帰、Cox回帰を使いたい場合は、glmnetパッケージのマニュアルを読みましょう。



*参考文献 [#i630eb1c]

この本の7.17節「LASSO」を参考にしています。

#html{{
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="https://rcm-fe.amazon-adsystem.com/e/cm?ref=tf_til&t=tohgorohmatsu-22&m=amazon&o=9&p=8&l=as1&IS2=1&detail=1&asins=4320057082&linkId=f6db5311dcfd9a82f5dee20859d39574&bc1=ffffff&lt1=_blank&fc1=444b4c&lc1=444b4c&bg1=ffffff&f=ifr"></iframe>
}}


Lasso回帰とRidge回帰については、この本に詳しく載っています。
この本は統計学習の教科書で、著者はglmnetパッケージの開発者です。

#html{{
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=tohgorohmatsu-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=0387848576&linkId=e1a6aca8e31e85c14d0315be0af71edf"></iframe>
}}

glmnetパッケージのソース、バイナリー、マニュアルがCRANからダウンロードできます。
-[[glmnet: Lasso and elastic-net regularized generalized linear models:http://cran.r-project.org/web/packages/glmnet/index.html]] | CRAN

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS