Rのニューラルネットパッケージ「neuralnet」を使ってみる

この記事は[フロムスクラッチ Advent Calendar 2016](http://qiita.com/advent-calendar/2016/fromscratch)の11日目の記事です。

最近はPythonでTensorFlowやChainerを使ってみることが流行っていますが、今回はあえてRのニューラルネットパッケージである[neuralnet](https://cran.r-project.org/web/packages/neuralnet/index.html)を使ってみました。

公式リファレンスの[neuralnet.pdf](https://cran.r-project.org/web/packages/neuralnet/neuralnet.pdf)にあるサンプルコードを参考にします。

# 想定読者

- ニューラルネットを勉強をしたことがある人
- 統計学の勉強をしたことがある人
- Rを触ったことがある人
- Rでニューラルネットを使いたい人

# 準備

パッケージをインストールします。

```
> install.packages("neuralnet")
> library("neuralnet")
```

# XOR問題

単純パーセプトロンでは学習できない、XORの学習をします。
まずは、データの準備。

```
> XOR <- c(0,1,1,0)
> xor.data <- data.frame(expand.grid(c(0,1), c(0,1)), XOR)
```

xor.dataはこのようになっています。

```
> xor.data
  Var1 Var2 XOR
1    0    0   0
2    1    0   1
3    0    1   1
4    1    1   0
```

そして、ニューラルネットを構築します。

```
net.xor <- neuralnet(XOR~Var1+Var2, xor.data, hidden=4, rep=5)
```

第1引数はモデル、第2引数は訓練データです。また、`hidden`では隠れニューロンの数を指定し、`rep`は訓練の回数を指定します。
（リファレンスでは隠れニューロンを2としていましたが、学習の精度が低かったので4にしています。）

ネットワークとしてはこのようになります。

```
> plot(net.xor, rep="best")
```

![image](https://qiita-image-store.s3.amazonaws.com/0/61088/8fb4481f-58e8-d3d4-c10d-e48843a8bb40.png)

`rep="best"`によって誤差が最も小さかったものをプロットしています。

net.xorが正しくXORを表すことを確認します。

```
> xor.data[-3]
  Var1 Var2
1    0    0
2    1    0
3    0    1
4    1    1

> compute(net.xor, xor.data[-3])$net.result
                [,1]
[1,] -0.005591322981
[2,]  0.991365312571
[3,]  1.003765769383
[4,]  0.006757999021
```

4つの入力に対して、それぞれ概ね正しい答えが得られました。

# 不妊データのロジスティック回帰

次は不妊に関するデータを扱います。
（センシティブなデータですが、リファレンスで使っていたので。。）

```
> data(infert, package="datasets")
> infert
    education age parity induced case spontaneous stratum pooled.stratum
1      0-5yrs  26      6       1    1           2       1              3
2      0-5yrs  42      1       1    1           0       2              1
3      0-5yrs  39      6       2    1           0       3              4
4      0-5yrs  34      4       2    1           0       4              2
5     6-11yrs  35      3       1    1           1       5             32
6     6-11yrs  36      4       2    1           1       6             36
7     6-11yrs  23      1       0    1           0       7              6
8     6-11yrs  32      2       0    1           0       8             22
9     6-11yrs  21      1       0    1           1       9              5
10    6-11yrs  28      2       0    1           0      10             19
11    6-11yrs  29      2       1    1           0      11             20
12    6-11yrs  37      4       2    1           1      12             37
13    6-11yrs  31      1       1    1           0      13              9
14    6-11yrs  29      3       2    1           0      14             29
15    6-11yrs  31      2       1    1           1      15             21
16    6-11yrs  27      2       2    1           0      16             18
17    6-11yrs  30      5       2    1           1      17             38
18    6-11yrs  26      1       0    1           1      18              7
19    6-11yrs  25      3       2    1           1      19             28
20    6-11yrs  44      1       0    1           1      20             17
...(省略)
 [ reached getOption("max.print") -- omitted 123 rows ]
```

データの説明は[こちら](http://www.is.titech.ac.jp/~mase/mase/html.jp/temp/infert.jp.html)をご参照ください。
自然・人工流産後の不妊症についてのデータです。

ネットワークを構築します。

```
net.infert <- neuralnet(case~parity+induced+spontaneous, infert,　err.fct="ce", linear.output=FALSE, likelihood=TRUE)
```

被験者か対照群かを表す`case`を目的変数とし、`parity`（実験回数？）、`induced`（人工流産）、`spontaneous`（自然流産）を説明変数（共変量）としたモデルです。
`err.fct`は誤差関数を指定します。`ce`の場合はクロスエントロピーで、`sse`の場合は二乗誤差となります。デフォルトでは二乗誤差です。
`linear.output`は`act.fct`を出力層のニューロンに適用しない場合は`TRUE`に、適用する場合は`FALSE`にします。
`act.fct`は活性化関数を指定します。デフォルトではロジスティック関数となります。
`likelihood`が`TRUE`のとき、誤差関数が負の対数尤度と同等となる場合に情報量規準のAICとBICが計算されます。

次に`gwplot`で各共変量の目的変数に対するGeneralized Weightをプロットします。

```
> par(mfrow = c(1,3))
> gwplot(net.infert, selected.covariate="parity", max=3.5, min=-2)
> gwplot(net.infert, selected.covariate="parity", max=3.5, min=-2)
> gwplot(net.infert, selected.covariate="induced", max=3.5, min=-2)
> gwplot(net.infert, selected.covariate="spontaneous", max=3.5, min=-2)
```

![image](https://qiita-image-store.s3.amazonaws.com/0/61088/e663d215-1a27-5300-a482-f44c3ed629ce.png)

Generalized Weightは共変量の目的変数への影響度を表しています。0付近に集まる場合は余り影響を与えないことを表します。
`spontaneous`は他と比較すると影響度が大きいのかもしれません。

最後に`confidence.interval`でGeneralized Weightの信頼区間とNICを計算します。

```
confidence.interval(net.infert)
$lower.ci
$lower.ci[[1]]
$lower.ci[[1]][[1]]
              [,1]
[1,]  0.2378732931
[2,] -0.7767930421
[3,] -5.6821658449
[4,] -8.7671639096

$lower.ci[[1]][[2]]
              [,1]
[1,] -0.7548627922
[2,] -6.4897821363



$upper.ci
$upper.ci[[1]]
$upper.ci[[1]][[1]]
             [,1]
[1,] 2.8480852032
[2,] 4.5389670051
[3,] 0.7944060804
[4,] 1.0157270261

$upper.ci[[1]][[2]]
              [,1]
[1,]  4.3246718745
[2,] -0.7591746629



$nic
[1] 135.6941297
```

# 次にやりたいこと

Rのニューラルネットパッケージは他にも「[nnet](https://cran.r-project.org/web/packages/nnet/index.html)」というものがあるので、次はそれを触ってみようかと思います。

# 参考

https://cran.r-project.org/web/packages/neuralnet/neuralnet.pdf