kerasでsin波の予測

#はじめに

```
import pandas as pd
import numpy as np
import math
import random
from keras.models import Sequential  
from keras.layers.core import Dense, Activation  
from keras.layers.recurrent import LSTM
import matplotlib.pyplot as plt
```

#パラメータの定義
```
# 乱数の係数
random_factor = 0.05
# サイクルあたりのステップ数
steps_per_cycle = 80
# 生成するサイクル数
number_of_cycles = 50
#配列の長さ
length_of_sequences = 100　
#ニューロン
in_out_neurons = 1
#隠れ層
hidden_neurons = 300
```
#乱数の係数

###乱数のシード値固定

```
random.seed(0)
```
シード　(種)の値はそのセットの番号です。0であれば0番の乱数が生成され、100であれば100番の乱数が生成されます。
#pandasの解説
###0から4000までのsinの各値を入れる箱(セル)を作成

```
df = pd.DataFrame(np.arange(steps_per_cycle * number_of_cycles +1), columns=["t"])
```

カラム名（列名）がtのデータフレームを作ります。ここでステップ数分のセルを作りたいのでサイクルあたりのステップ数にサイクル数をかけることで4000個のデータができますが、データフレームのロー(行)は0から始まるので最後に+1してあげることでセル数は4001個となりますが最後の行名は4000ちょうどになります。
np.arange()はnumpy形式で0から()の中身の数だけ整数を生成する関数です。


###次に作ったデータフレームの箱(セル)の中にsinのステップ数に応じたデータを入力

```

df["sin_t"] = df.t.apply(lambda x: math.sin(x * (2 * math.pi / steps_per_cycle)+ random.uniform(-1.0, +1.0) * random_factor))
```
df[""]としてあげることで事前に作らずともそのカラム名を指定することができます。そして、そのカラムに先ほど作ったステップ数の行に対応するsinの値を入れていきます。
・「df.t.apply()」は「データフレームのカラム「t」の各セルを()の中に入力する」と言う意味です。
・「lambda x:」は「入力されたがるxを:から定義している」と言う意味になります。
つまり、これら二つを合わせると『カラム「t」の各セルをxに入力する』と言う意味になります。
sinθのθの中にこれらの値と他にノイズを入れてあります。random.uniform(A,B)は小数点を含むA以上B以下の乱数を生成します。random_factorを掛けることでその影響力、つまりノイズの大きさを調整することができます。
###作ったデータフレームをグラフに出力

```
df["sin_t"].head(steps_per_cycle * 2).plot()
plt.show()
```
df.head()は()中の値だけをセル値を取得する関数です。ここでは「サイクルあたりのステップ数」×2、sinの2周期分のsin波のデータを取得しています。
.plot()でその値をグラフにします。しかし、グラフをディスプレイに表示させるにはplt.show()が必要となります。

#訓練データの解説
###訓練データの作成

```
def _load_data(data, n_prev = 100):  
    #空リスト作成
    docX, docY = [], []
    #0から(len(data)-n_prev)だけの整数が配列としてある
    for i in range(len(data)-n_prev):#3501個のデータ分
        #doc配列にi個目からi+100番目のデータを行列の形にして入れていく
        docX.append(data.iloc[i:i+n_prev].as_matrix())#3501~3601
        docY.append(data.iloc[i+n_prev].as_matrix())
    #numpyで扱えるように行列をその形にして再定義
    alsX = np.array(docX)
    alsY = np.array(docY)
    return alsX, alsY
```
data引数
用意した空のリストにnumpy形式の各行列データを入力します。
ここで、as_matrix()を使うことでそのデータの形式をnumpyの行列にしてくれます。

#テストデータの解説
###訓練データとテストデータを分ける
```
def train_test_split(df, test_size=0.1, n_prev = 100):  
    ntrn = round(len(df) * (1 - test_size))#3601個
    ntrn = int(ntrn)
　　　　　　　　#訓練データは0〜３６０１
    X_train, y_train = _load_data(df.iloc[0:ntrn], n_prev)
    #テストデータは3601〜
　　　　　　　　X_test, y_test = _load_data(df.iloc[ntrn:], n_prev)
    return (X_train, y_train), (X_test, y_test)
```
round()は()中の値の小数点以下を四捨五入する関数です。
len()でdfの行数を取得します。
「test_size=0.1」はテストデータを１割取って置くこと意味するため、「1 - test_size」で9割りと言う意味になります。
4001個の9割なので訓練データは四捨五入して3601個になります。
対してテストデータは3601個から最後までと言う意味になります。

```
(X_train, y_train), (X_test, y_test) = train_test_split(df[["sin_t"]], n_prev =length_of_sequences) 
```
#モデルの追加
```
model = Sequential()  #おまじない
model.add(LSTM(hidden_neurons, batch_input_shape=(None, length_of_sequences, in_out_neurons), return_sequences=False))
#Noneとうすることで値をしてせず、任意の数でバッチサイズをきめることができる
#一つの入力で100のリスト
#in_out_neuronsは出力の数
  
#入力値の個数に対して１つの出力
model.add(Dense(in_out_neurons)) 
#活性化関数linear
model.add(Activation("linear"))
#コンパイル
model.compile(loss="mean_squared_error", optimizer="rmsprop")

model.fit(X_train, y_train, batch_size=60, nb_epoch=3, validation_split=0.05)
b
```
X_train, y_trainは先ほど作ったデータになります。
batch_size=60は１セットあたりのサンプル数、nb_epoch=3は訓練データを使い切る回数を表しています。
fitの中にも訓練と検証データが必要でvalidation_split=0.05は全データの内0.05(5%)が検証用として扱われます。

#結果の表示
```
dataf =  pd.DataFrame(predicted[:200])
dataf.columns = ["predict"]
dataf["input"] = y_test[:200]
#dataf.plot(figsize=(15, 5))
print(str(dataf))
dataf.plot()
plt.show()
```