機械学習を1ヵ月で実践レベルにする #6 (Octave 実践編)

# 6日目
理論を理解しても、それをOctave で実装するときにつまづくことが結構ありました。特に実数(スカラー)での定義をベクトルや行列に拡張するときに、式では理解できても、Octave で表現するときにつまづくことが多かったです。

Vectorial implementation という考え方があると少し理解しやすくなると思いましたので、ここで1日使って、このVectorial implementation を説明したいと思います。

## 過去記事一覧
* [1日目 とっかかり編](http://qiita.com/junichiro/items/ee50af10df77d52cd432)
* [2日目 オンライン講座](http://qiita.com/junichiro/items/7a5b95d7122176e94fe0)
* [3日目 Octave チュートリアル](http://qiita.com/junichiro/items/33954f08411e33d33506)
* [4日目 機械学習の第一歩、線形回帰から](http://qiita.com/junichiro/items/d4dc67bdebb9fccb7ef5)
* [5日目 線形回帰をOctave で実装する](http://qiita.com/junichiro/items/1a4b87e99b471cf5bea1)
* [6日目 Octave によるVectorial implementation](http://qiita.com/junichiro/items/7972b1b6ad3d087fbde0)
* [7日目 ロジスティック回帰 (分類問題) その1](http://qiita.com/junichiro/items/8de94c84c35e9851d42a)
* [8日目 ロジスティック回帰 (分類問題) その2](http://qiita.com/junichiro/items/5d20a40a3a282af422a3)
* [9日目 オーバーフィッティング](http://qiita.com/junichiro/items/4d2c91128c9bd850f580)
* [10日目 正規化](http://qiita.com/junichiro/items/8b1867201663c5af38a4)
* [11日目 ニューラルネットワーク #1] (http://qiita.com/junichiro/items/7794cedf834a4f6ef52c)
* [12日目 ニューラルネットワーク #2] (http://qiita.com/junichiro/items/b522ea41c02f90d23aa5)
* [13日目 機械学習に必要な最急降下法の実装に必要な知識まとめ](http://qiita.com/junichiro/items/527b1f211ed814528ded)
* [14日目 機械学習で精度が出ない時にやることまとめ](http://qiita.com/junichiro/items/7e2842c7afba2407c49b)
* [最終日 機械学習をゼロから1ヵ月間勉強し続けた結果](http://qiita.com/junichiro/items/3457e33e502086a200f1)

## Octave によるVectorial implementation
例によって、英語しかみていないので「Vectorial implementation」日本語の該当する用語がわかりません。Google によると「ベクトル化実装」らしいです。どうもピンと来ませんが、Octave で数値計算するときに大事な考えかたなので、さっとまとめておきます。

## 早速
![image](https://qiita-image-store.s3.amazonaws.com/0/121876/3a9cd6ca-f8a9-f8a1-0422-e5d366200dc4.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/121876/9d0018f9-6407-2422-5575-569562679174.png)

このように要素数が同じ配列が2つあったとします。そこでいま

![image](https://qiita-image-store.s3.amazonaws.com/0/121876/905e1df6-7317-60a5-9126-753735c3a91c.png)

これを計算したいと思います。∑ を使って書くとこうなります。

![image](https://qiita-image-store.s3.amazonaws.com/0/121876/3da92691-5053-95af-89f7-df507017e42d.png)

## 愚直に考えてループ
### Python
```python

a = [1, 2, 3]
b = [2, 3, 4]
ans = 0
for i, v in enumerate(a):
    ans = ans + a[i] * b[i]
print(ans)
```
### Octave
```octave
a = [1;2;3]
b = [2;3;4]
ans = 0
for j = 1:length(a)
    ans = ans + a(j) * b(j);
end
display(ans)
```

∑ の計算はfor ループで書くのは直感的かと思います。

## 行列の積として考える
しかし、

![image](https://qiita-image-store.s3.amazonaws.com/0/121876/905e1df6-7317-60a5-9126-753735c3a91c.png)

この形は行列の積で表すこともできます。

![image](https://qiita-image-store.s3.amazonaws.com/0/121876/7b1f0dd0-ee78-6ba3-77fa-3ceef1220d1f.png)

Octave は行列の計算に長けていますから、さきほどのコードにあるa やb は行列としても扱えます。Octave の場合、配列はベクトルで、要素nのベクトルというのは n x 1 の行列に過ぎませんから、a, b はそれぞれこうなっています。

![image](https://qiita-image-store.s3.amazonaws.com/0/121876/c8dc708b-271e-485d-1696-c8371f79a889.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/121876/e0c013ba-7909-4db6-c4d3-8774d1efd20c.png)

両方 3 x 1 では行列の積が作れませんので、片方を転置(T)して

![image](https://qiita-image-store.s3.amazonaws.com/0/121876/00900a38-9df4-42f0-7850-b94799fa3263.png)

このようにも表現できることがわかります。これをOctave のコードに落とすと

```octave
a = [1;2;3]
b = [2;3;4]
ans = a' * b
display(ans)
```
実際に計算している部分はa を転置してb に掛けるだけ。

```octave
a` * b
```
これでできます。これがベクトル化実装です。
コード自体がすっきりかけるだけでなく、Octave の内部で効率の良い行列計算がなされますから、実行効率もよくなります。機械学習では∑ の計算は結構でてきますので、効率の良いベクトル化実装がすぐに思い浮かぶようになるといいですね。