1.【準備編】NNの使い方を身につけよう！

# はじめに
少し前から機械学習、特にディープラーニングの勉強をしています。

理解を深めるには自分でコーディングしてみるのが良い、と考え慣れ親しんできたObjective-Cで色々とコーディングしてみました。ある程度理解できてCNNによる手書き数字認識ができ、次に何をしようか、というタイミングで自作のツールの拡充はやめてpython3とkerasを使用することにしました。ずっと速そうだったからです。

pythonもkerasも不慣れなので、忘備録として、いつもお世話になっているQiitaに投稿することにしました。

お気付きの点がありましたらご指摘いただけますと幸いです。

##課題
全4回のシリーズでは、以下の3つの課題をクリアしたいと思います。

1. 平均と標準偏差を出力するNN
2. 正規分布に従う波形データから、その正規分布を描画するのに必要な3つのパラメータを出力するNN
3. 画像中にある円についての4つのパラメーター(x座標、y座標、半径、線の太さ)を出力する畳み込みNN(CNN)

第1回の今回は準備編です。

##numpyのndarrayの使い方の復習
kerasを用いるには、学習用のデータをnumpyのndarray(N次元の配列)として準備する必要があり、ndarrayの取り扱いについて、あれこれ知っておく必要があります。
まずはnumpyをimportします。

```001.py
# numpyのimport
import numpy as np
# numpyの配列を作って変数aに格納。角括弧を忘れるとダメ。
a = np.array([1,2,3,4,5,6])  #良い
a = np.array(1,2,3,4,5,6)    #ダメ
# 配列の中身を確認するには
a
# array([1, 2, 3, 4, 5, 6])
```
numpyのndarrayを取り扱う時は、その形(shape)を意識する必要があります。shapeを確認してみます。

```002.py
#行列の形(shape)を確認するには、
a.shape     #良い　(6,)
a.shape()   #ダメ。エラーが出ます。
np.shape(a) #これでも良い。
```
a.shape()ではなくて、a.shapeなのでndarrayの属性(attributes)の1つということでしょうか。
続いて行列の形(shape)をreshape()で変更してみます。

```003.py
a.reshape(2,3)     #ダメ...shapeが変わったものが返されるが、a自身は変わらない。
# array([[1, 2, 3],
#        [4, 5, 6]])

a = a.reshape(2,3) #良い
```
a.reshape(2,3)は新しくndarrayを作って返すので、ここでは同じ変数aに入れなおしています。メソッドによって、新しいndarrayが作られるのか、既存のndarrayが変更されるのか、区別する必要があります。
##ndarrayの部分を取り出す方法(1次元配列)
続いてndarrayからのデータの取り出し方です。新しくndarrayを1つ作ります。

```004.py
b = np.arange(10) #array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
b[2:5] # array([2, 3, 4]) indexは0から始まっており、5番目は含まれない。
b[3:]  # array([3, 4, 5, 6, 7, 8, 9]) index 3から最後まで。
b[:4]  # array([0, 1, 2, 3]) index 4の直前まで。
b[:]   # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])。全部。
b[-4:] # array([6, 7, 8, 9]) 後ろから4つ目から最後まで。
b[:-4] # array([0, 1, 2, 3, 4, 5]) 後ろから4つ目まで(後ろから4つ目は含まれない)。
```
##ndarrayの部分を取り出す方法(3次元配列)
続いて3次元のndarrayについてです。ここで示す例は要素数30とちょっと大きいndarrayです。3つの次元の要素数が「互いに素」になるようにするとわかりやすいかなと思って30ですが、それ以外に30にあまり意味はありません。

```005.py
c = np.arange(30).reshape(5,3,2) #np.arange(30)で作ったndarrayを、(変数にしまわずに)reshapeして変数cに入れる。
c
# array([[[ 0,  1],
#         [ 2,  3],
#         [ 4,  5]],
# 
#        [[ 6,  7],
#         [ 8,  9],
#         [10, 11]],
# 
#        [[12, 13],
#         [14, 15],
#         [16, 17]],
# 
#        [[18, 19],
#         [20, 21],
#         [22, 23]],
# 
#        [[24, 25],
#         [26, 27],
#         [28, 29]]])
```
これを5つのトレーニングデータだと思って2つ目(index 1)を取り出すには、

```006.py
c[1,:,:]
# array([[ 6,  7],
#        [ 8,  9],
#        [10, 11]])
```

index 3まで(index 3は含まれない)を取り出すには、

```007.py
c[:3,:,:]
# array([[[ 0,  1],
#         [ 2,  3],
#         [ 4,  5]],
# 
#        [[ 6,  7],
#         [ 8,  9],
#         [10, 11]],
# 
#        [[12, 13],
#         [14, 15],
#         [16, 17]]])
```

index 3からを取り出すには、

```008.py
c[3:,:,:]
# array([[[18, 19],
#         [20, 21],
#         [22, 23]],
# 
#        [[24, 25],
#         [26, 27],
#         [28, 29]]])
```
とします。

##ndarrayに要素を追加する方法

```009.py
np.append(c,100) #1次元のndarrayが新たに作られて返される。
#要素を追加したもので自身を置き換えるには、
c = np.append(c,100) #とする。
#中身の確認
c
# array([  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,
#         13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,
#         26,  27,  28,  29, 100])
```
ただし上記の方法は、追加する要素数が多数の場合は使うべきではありません。ndarrayを新しくなんども作るのは、それなりにCPU/メモリ負荷が高いからです。要素を多数含むようなndarrayを作成する場合は、pythonの配列(リスト)をまず作成し、それを使ってndarrayを作るようにします。

```010.py
#遅い方法
d = np.array([]) #空のndarray
for i in range(100000):
    d = np.append(d,i)
#早い方法
d = [] #空のリスト
for i in range(100000):
    d.append(i)
d = np.array(d)
#短く書くなら
d = np.array([i for i in range(100000)])
```

#まとめ
ndarrayを、作り、形を変え、分割して取り出すことができるようになりました。
[シリーズ第1回 準備編](https://qiita.com/yoho/items/e8dffd640405b0a94fc0)
[シリーズ第2回 平均と標準偏差](https://qiita.com/yoho/items/e9a65b10ca510ab50a36)
[シリーズ第3回 正規分布](https://qiita.com/yoho/items/46a98c2aa28afe464146)
[シリーズ第4回 円](https://qiita.com/yoho/items/c41c7ea8cba979ed72c7)