RNNを用いた気温の予測

とある課題でRNNを使った気温の予測をしようと思ったのですが、（詳しくは後述しますが）結果が微妙だったので没になりました。なので、ここで没供養させていただければと思います。

# 概要
気象庁の観測データを基にRNNを使用して平均気温の将来予測をします。
得られたデータをちょっと考察します
筆者が実行したコードは [github](https://github.com/eycjur/portfolio/blob/master/rnn/rnn.py) においてあります

# ライブラリのインポート

```python:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score

from keras.layers.recurrent import SimpleRNN
from keras.models import Sequential
from keras.optimizers import Adam
from keras.layers import Dense, Activation
from tensorflow.keras.callbacks import EarlyStopping
```
ここは特に言うことはないですかね

# データの取得
データは [気象庁のHP](https://www.data.jma.go.jp/gmd/risk/obsdl/index.php) からダウンロードできます。~~ちなみに筆者は諸事情で別に入手しました~~。
ダウンロードしたデータには品質情報と均質番号があると思いますが、これは基本的に無視して大丈夫です。
あと一度にダウンロードできるデータ数に制限があるので、20年ごとに分割してダウンロードしたものをpandasで結合しました。

```python:

# 読み込み
tokyo1=pd.read_csv("data/tokyo_1961-1980.csv", header=2,skiprows=[4],encoding="shift-jis",parse_dates=["年月日"])
tokyo2=pd.read_csv("data/tokyo_1981-2000.csv", header=2,skiprows=[4],encoding="shift-jis",parse_dates=["年月日"])
tokyo3=pd.read_csv("data/tokyo_2001-.csv", header=2,skiprows=[4],encoding="shift-jis",parse_dates=["年月日"])
tokyo=pd.concat([tokyo1, tokyo2, tokyo3], ignore_index=True)
tokyo=tokyo.sort_values("date", ignore_index=True)
tokyo["year"]=tokyo["年月日"].dt.year
```

日時情報をdatetime型にしたいので`parse_dates=["年月日"]`としています。なお筆者はこのコードで実行していないのでどっか間違ってたらごめんなさい

# データの整形

```python:
#整形
tem=tokyo["avtem"]
timesteps = 20

x = np.empty([len(tem)-timesteps, timesteps], dtype=np.float32)
y = np.empty(len(tem)-timesteps, dtype=np.float32)

for i in range(len(x)):
    x[i] = tem[i:i+timesteps].T
    y[i] = tem[i+timesteps]

data_len = timesteps*int(len(x)/timesteps)

x = x[:data_len].reshape(data_len,timesteps,-1)
y = y[:data_len].reshape(data_len,-1)
x_train=x[:21164]
y_train=y[:21164]
x_test=x[21164:21529]
y_test=y[21164:21529]
```
データの整形は [これ](https://helve-python.hatenablog.jp/entry/keras-stateful-rnn) を参考にしました。
trainデータは2018年までのもの、testデータは2019年のものを手動で行番号を探して取り出しました(1961年1月1日からのデータを用いると同じ行数になると思います)。

# モデルの作成
```python:
#モデルの作成
model = Sequential()
model.add(SimpleRNN(50, input_shape=(timesteps, 1), kernel_initializer='random_normal'))
model.add(Dense(1))
model.add(Activation('linear'))

model.compile(loss='mean_squared_error', optimizer=Adam(lr=0.01, beta_1=0.9, beta_2=0.999))
early_stopping = EarlyStopping(monitor='val_loss', mode='auto', patience=3)
model.fit(x_train, y_train, batch_size=1024, epochs=20, validation_split=0.1,callbacks=[early_stopping])

y_pred = model.predict(x_test)
print("RMSE:",np.sqrt(mean_squared_error(y_test, y_pred)))
print("r2  :",r2_score(y_test,y_pred),"\n")

```
モデルの作成では [これ](https://www.infiniteloop.co.jp/blog/2018/02/learning-keras-07/) を参考にしました。trainデータ数が2万以上あったので、バッチサイズ512と大きめに設定しています。
これを実行すると、12回ぐらいで精度が上がらくなり、スコアは、

- RMSE: 2.0795848
- r^2  : 0.9290615357147783 

でした。 [気象庁の予測精度](https://www.data.jma.go.jp/fcd/yoho/kensho/yohohyoka_top.html) が最高気温でRMSE1.5強なので精度があまりよくないことがわかります。
特にちょっと考えてもらえばわかると思いますが平均気温は最高気温に比べてぶれにくいので平均気温でこんだけの誤差が出てしまうのではちょっと使い物にならない感がすごいです。なお、実際にこのプログラムを最高気温でやってみるとRMSE3.2程度でした。

# 考察（というほどでもないですが）
テストデータ（2019年）の気温予測と実際の値を比較してみました。
![pic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678160/7e6bafd1-f8d1-c1c2-d07c-8dfa49816ab2.png)
主に上下に大きく変動しちゃったとこが予測できていないことがわかります。これは過去のデータから傾向で予測しているという都合上しょうがないと思います。
そもそも気温というか天気は気圧配置などに影響されるわけで、それに明確にパターンが決められているのかといえばそうではない気がするので、気象庁は様々な観測データから数値計算して気温を求めてるのでパターンがなくても予測することが可能であることを考えると、RNNでそこまでの精度は出ないのかなという気がします。

ちなみにもっと一部分を拡大してみるとこんな感じでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678160/c02c85d9-d89c-60d3-fd16-b12b895c7869.png)
~~いや、予測しているというより、前日の観測データの後追いしてるだけやん~~

# 参考文献
- [初心者のRNN(LSTM) | Kerasで試してみる]
(https://qiita.com/sasayabaku/items/b7872a3b8acc7d6261bf)
- [気象庁HP「天気予報の精度検証結果」]
(https://www.data.jma.go.jp/fcd/yoho/kensho/yohohyoka_top.html)
- [infiniteloop「入門 Keras (7) 最終回：リカレントニューラルネットワークを体験する」]
(https://www.infiniteloop.co.jp/blog/2018/02/learning-keras-07/)
- [Helve’s Python memo「KerasのステートフルRNNで学習を高速化する」]
(https://helve-python.hatenablog.jp/entry/keras-stateful-rnn)