[Deep Learning解析]　第二回　天気予報によりRNN

RNNは深層学習の中でも結構難しいモデルである。time-step, feature-size, batch-sizeなどhyper-parametersで迷う人もおる。
今日、理解しやすくして天気予報を例にして時系列のデータでRNNを説明したいと思います。

# データ
[気象庁](https://www.data.jma.go.jp/gmd/risk/obsdl/index.php)のDownloadサイトからある県の最近１０年の天気を使います。（一回で１０年のデータをDownloadできないので、わけってdownloadした方がいい）

## データの洗い出し
```python
import pandas as pd

train = pd.read_csv("./older.csv",sep=',')# older.csv は2009年からのデータになります、学習用
test = pd.read_csv("./new.csv",sep=',')# new.csv は2014年からのデータになります、テスト用

train=train.dropna()#データの中でNaN値がありますので、取りぬきます
test=test.dropna()#データの中でNaN値がありますので、取りぬきます
```
この時点でデータを見てみると

```python
train.head()
```

|	|Date|	Temp|	Total rainfall(mm)|	Day time(hour)|	Average wind speed(m/s)|	Average vapor pressure(hPa)|	Average cloud cover|	Average local atmospheric pressure(hPa)|
|---|---|---|---|---|---|---|---|---|
|0|	2009/1/1|	5.1|	0.0|	2.3|	4.9|	4.9|	5.3|	1013.4|
|1|	2009/1/2|	6.6|	0.0|	4.1|	4.3|	5.4|	4.3|	1018.6|
|2|	2009/1/3|	6.7|	0.0|	3.3|	2.6|	5.2|	4.8|	1023.2|
|3|	2009/1/4|	7.1|	0.0|	8.4|	2.1|	5.6|	4.0|	1021.7|
|4|	2009/1/5|	9.0|	0.0|	2.2|	2.6|	6.9|	7.3|	1019.0|


plotしていましょう

```python
train.plot(subplots=True, figsize=(18,28), layout=(7,1))
```
![all.png](https://qiita-image-store.s3.amazonaws.com/0/148692/704e80b3-0fd9-6543-9b6e-6aec7647a845.png)

## 予測データの作り

Dateが温度との関係性が複雑なので、一様使わないと判断します、抜きます。

```python
train=train.drop(["Date"], axis=1)
test=test.drop(["Date"], axis=1)

```

**二日後の温度を予測するモデルをつくりますので、target dataを二日shiftをします**

```python

target_names = ['Temp']#予測したい特徴
shift_days = 2
Y_train = train[target_names].shift(-shift_days)
Y_test = test[target_names].shift(-shift_days)
```

![shift.JPG](https://qiita-image-store.s3.amazonaws.com/0/148692/c7580e06-b374-6b1b-5ad7-4e0ed8777fad.jpeg)

それの結果は、データの最後の二行がNaNなってしまう、それを抜きます。入力もそれに合わせます。

```python
Y_train = Y_train.values[:-shift_days]
Y_test = Y_test.values[:-shift_days]
X_train_np = train.values[0:-shift_days]
X_test_np = test.values[0:-shift_days]
```

## データの正規化

```python
from sklearn.preprocessing import MinMaxScaler

x_scaler = MinMaxScaler()
x_train_scaled = x_scaler.fit_transform(X_train_np)
x_test_scaled = x_scaler.transform(X_test)#テストデータも同じ領域で正規化します（同じ正規器を使う）
num_train = x_train_scaled.shape[0]

y_scaler = MinMaxScaler()
y_train_scaled = y_scaler.fit_transform(Y_train)
y_test_scaled = y_scaler.transform(Y_test)#テストデータも同じ領域で正規化します（同じ正規器を使う）

validation_data = (np.expand_dims(x_test_scaled, axis=0),
                   np.expand_dims(y_test_scaled, axis=0))#評価用
```

## RNN

```python
def batch_generator(batch_size, sequence_length):
    while True:
        x_shape = (batch_size, sequence_length, num_x_signals)
        x_batch = np.zeros(shape=x_shape, dtype=np.float16)

        y_shape = (batch_size, sequence_length, num_y_signals)
        y_batch = np.zeros(shape=y_shape, dtype=np.float16)

        for i in range(batch_size):
            idx = np.random.randint(num_train - sequence_length)
            
            x_batch[i] = x_train_scaled[idx:idx+sequence_length]
            y_batch[i] = y_train_scaled[idx:idx+sequence_length]
        
        yield (x_batch, y_batch)
```
RNNで入力データは（batch, sequence_length, feature）になるので、↑のbatch_generatorを使って、batch_sizeごとにデータを分ける。

```python
##シーケンス長28を使用します。これは、各ランダムシーケンスに1月の観測値が含まれていることを意味します。 1つの時間ステップは1日に対応するので、7つの時間ステップは1週間に対応し、7×4は1月に対応する。

batch_size = 32
sequence_length =  7 * 4
generator = batch_generator(batch_size=batch_size,
                            sequence_length=sequence_length)
```

**RNN(GRU)作成**
シーケンスの各タイムステップごとに128個の出力があるGated Recurrent Unit（GRU）のネットワークを追加します。The GRU が128個のoutputです、しかし私たちが予測したいのは温度だけなので、denseを使って１outputにまとめます. 出力データは[0,1]の間で正規化していますので、Sigmoidを使って予測範囲も[0,1]にしたほうが計算が下がります、reluとかはもつかいます、しかしtanhは使えないので（なぜ）気をつけてください(正規化の範囲が[0,1]なので)

```python
from keras.models import Sequential
from keras.layers import Input, Dense, GRU, Embedding
from keras.optimizers import RMSprop


model = Sequential()
model.add(GRU(units=128,
              return_sequences=True,
              input_shape=(None, num_x_signals,)))
model.add(Dense(num_y_signals, activation='sigmoid'))
model.compile(loss="mse", optimizer='adam')

model.summary()
```
```bash
Layer (type)                 Output Shape              Param #   
=================================================================
gru_1 (GRU)                  (None, None, 128)         52224     
_________________________________________________________________
dense_1 (Dense)              (None, None, 1)           129       
=================================================================
Total params: 52,353
Trainable params: 52,353
Non-trainable params: 0
_________________________________________________________________
```
```python
model.fit_generator(generator=generator,
                    epochs=5,
                    steps_per_epoch=100,
                    validation_data=validation_data)
```

**天気予報**
最後に学習したモデルを使って、予測してみましょう。

```python
#This code credit goes to https://github.com/Hvass-Labs
def plot_comparison(start_idx, length=100, train=True):
    """
    Plot the predicted and true output-signals.
    
    :param start_idx: Start-index for the time-series.
    :param length: Sequence-length to process and plot.
    :param train: Boolean whether to use training- or test-set.
    """
    
    if train:
        # Use training-data.
        x = x_train_scaled
        y_true = Y_train
    else:
        # Use test-data.
        x = x_test_scaled
        y_true = Y_test
    
    # End-index for the sequences.
    end_idx = start_idx + length
    
    # Select the sequences from the given start-index and
    # of the given length.
    x = x[start_idx:end_idx]
    y_true = y_true[start_idx:end_idx]
    
    # Input-signals for the model.
    x = np.expand_dims(x, axis=0)

    # Use the model to predict the output-signals.
    y_pred = model.predict(x)
    
    # The output of the model is between 0 and 1.
    # Do an inverse map to get it back to the scale
    # of the original data-set.
    y_pred_rescaled = y_scaler.inverse_transform(y_pred[0])
    
    # For each output-signal.
    for signal in range(len(target_names)):
        # Get the output-signal predicted by the model.
        signal_pred = y_pred_rescaled[:, signal]
        
        # Get the true output-signal from the data-set.
        signal_true = y_true[:, signal]

        # Make the plotting-canvas bigger.
        plt.figure(figsize=(15,5))
        
        # Plot and compare the two signals.
        plt.plot(signal_true, label='true')
        plt.plot(signal_pred, label='pred')
        
        # Plot grey box for warmup-period.
        p = plt.axvspan(0, 1, facecolor='black', alpha=0.15)
        
        # Plot labels etc.
        plt.ylabel(target_names[signal])
        plt.legend()
        plt.show()
```

学習で使ったデータで予測します

```python
plot_comparison(start_idx=1, length=1000, train=True)
```
![train.png](https://qiita-image-store.s3.amazonaws.com/0/148692/d5b34dcb-89bc-0774-5fd0-42aa023af888.png)

テストデータで予測します

```python
plot_comparison(start_idx=1, length=1000, train=False)
```
![test.png](https://qiita-image-store.s3.amazonaws.com/0/148692/29a92753-9f69-f6ca-685d-c668bc4975c9.png)