機械学習１年生が大阪市の気温予測に挑戦　〜理想と現実編〜

##はじめに
これは、機械学習１年生の私が気温予測に挑戦した軌跡である。
厳密に言うと、気温予測ではない(？)かも。（＞ 7.最後に で思う理由を説明）
理想では、予測の気温と実際の気温がかなり似る（特徴的な気温変動を捉えられているという意味）かと思ったが、現実は甘くなかった。

##お品書き
####1. 機械学習で使われる用語(メモ)<br>2. 手順<br>3. ソースコード<br>4. 結果<br>5. エラーの解決策<br>6. 参考書<br>7. 最後に

##1. 機械学習で使われる用語（メモ）

|用語|説明|
|:-:|:-:|
|ニューラルネットワーク|人工知能分野におけるアルゴリズムの中の１つであり、人間の脳の構造を模している。|
|バッチサイズ|データセットをいくつかのサブセットに分ける。（訓練用、テスト用とは別）<br>サブセットに含まれるデータ数を表す。|
|エポック数|次行1と2の手順を踏む回数のこと<br>1.　データセットをバッチサイズに従って、N個のサブセットに分ける。<br> 2. 各サブセットを学習に回す。 |
|最適化|損失関数を最小化するパラメータを求めること|
|活性化関数|ニューロンの線形結合後の非線形変換を行う関数|
|損失関数|出力と正解の誤差を求める関数|
|オプティマイザ(optimizer)<br>最適化アルゴリズム|損失関数の最小値を求めるアルゴリズム|

##2. 手順
1. 気象庁(https://www.data.jma.go.jp/gmd/risk/obsdl/ "気象庁|過去の気象データ・ダウンロード")より、2011~2020年の観測データを取得する。<br>（2011~2019年を訓練用、2020年をテスト用）<br>今回は、変数として気温、日照時間、全天日射量、降水量などを使用した。
![スクリーンショット 2021-07-01 14.35.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1470630/b8dc0c75-a5df-4de0-db30-426113f09ca2.png)

上記の様に、大阪市の気象データを取得した。開始行数は2行目からに調整している。<br>
2. 観測データのうち、2011~2019年分を使用することで、各変数の9年平均値を求める。<br>
3. 各変数において、偏差(ズレ)＝(2011年から2020年の観測値)ー(9年平均値)より、<br>10年分の日別偏差を求める。<br>
4. 気温以外の変数は、日別偏差を標準化する。<br>
5. モデル構築( 中間層：10層, 活性化関数：Linear, エポック数：50, バッチサイズ：50 )を行う。<br>
6. モデル学習( 学習率：0.001, 損失関数：mean_squared_error )を行う。<br>学習データは標準化された日別偏差(4を参照)と2011~2020年の日別気温偏差を使用した。<br>
7. 2020年の気温を予測する。予測気温＝(9年平均気温値)＋偏差(モデル学習で求めた値)から求める。<br>

##3. ソースコード
```python
import pandas as pd
import numpy as np
from sklearn import preprocessing
from sklearn.metrics import accuracy_score
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras import optimizers
from tensorflow.keras.optimizers import RMSprop
import matplotlib.pyplot as plt
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split

# csvファイルの読み込み
# ヘッダー行（１〜２行読み飛ばし）
#df = np.loadtxt('climate_osaka3.csv', skiprows=2, delimiter=",", dtype=float, encoding="utf-8_sig", usecols=[1,2,3,4,5,6,7])
df = np.loadtxt('climate_osaka3.csv', skiprows=2, delimiter=",", dtype=float, encoding="utf-8_sig", usecols=[1,2,3,4,5,6,7,8])
print(df)
k = 8 #列数

# 2011~2019年の日別平均値を求める
def mean(df1):
    return sum(df1) / len(df1)

# 2011~2019年の日別平均気温,現地気圧,降水量,日照量,湿度,雲量,全天日射量,風速を求める(うるう年も考慮)
df2 = np.zeros((366,k)) #日別平均値を求める
i2 = 0 #df2の行数カウント
while i2 <= 365:
    i = 0
    i1 = i2
    df1 = np.zeros((9,k)) # 各年の月別平均値を格納
    if ( i2 != 59 ): # 2/29以外
        while i <= 8:
            mod = i % 4
            if ( mod == 1 ): # 2012 2016
              #  print(i)
                df1[i,:] = df[i1,:]
                i1 = i1 + 366 
            else :
                df1[i,:] = df[i1,:]
                i1 = i1 + 365
            i = i + 1   
    else : # 2/29 
        while i <= 8:
            mod = i % 4
            if ( mod == 0 ): # 2011 2015   
                df1[i,:] = ( df[i1,:] + df[i1+1,:] ) / 2.0 # average 2/28 3/1  
                i1 = i1 + 366
            elif ( mod  == 1 ) : # 2012 2016
                df1[i,:] = df[i1,:] # 2/29
                i1 = i1 + 365
            else :  # 2013 2014 2017 2018 2019 
                df1[i,:] = ( df[i1,:] + df[i1+1,:] ) / 2.0 # average 2/28 3/1
                i1 = i1 + 365
            i = i + 1    
 #   print(i2)
    df2[i2,:] = mean(df1)
    i2 = i2 + 1

# 2011~2019年ズレ（各変数で同日の観測値と2011~2019年平均値からズレを求める）
i = 0
i1 = 0
df3 = np.zeros((3653,k)) #2011~2019年の平均値からのズレ
while i <= 3652:
    print(i,i1)
    df3[i,:] = df[i,:] - df2[i1,:] # ズレ（2020-ave）
    if ( i1 == 58 ) : # 2/28
        if ( ( i == 423 )  or ( i == 1884 ) or ( i == 3345) ) : # 2012 2016 2020 2/28
            i1 = i1 + 1 # not skip 2/29
        else : # not 2012 2016 2020 2/28
            i1 = i1 + 2 # skip 2/29      
    else : # not 2/28
        i1 = i1 + 1
    if ( i1 == 366 ) : # i1 
        i1 = 0
    i = i + 1
    
# モデルデータの準備
#　目的変数を取り出す(気温)
#　説明変数を取り出す（現地気圧、降水量、日照時間、湿度、雲量、全天日射量、風速）列ごとに標準化
import scipy.stats
y_train = df3[0:3286, 0] #2011~2019
y_test = df3[3287:3653, 0] #2020
x_train = scipy.stats.zscore(df3[0:3286, 1:k]) #2011~2019
x_test = scipy.stats.zscore(df3[3287:3653, 1:k]) #2020
print(x_test)

# モデルの構築(activate:filter)
model = Sequential() #simpile-line
model.add(Dense(10,input_shape=(k-1,),activation='sigmoid'))
model.add(Dense(1, activation='linear'))

# モデル学習
model.compile(optimizer=RMSprop(),loss='mean_squared_error')
model.fit(x_train, y_train, epochs=50, batch_size=50, verbose=2) #epochs=50, batch_size=50

# モデルを使った予測
y_pred = model.predict(x_test)

# ズレをもとにした2020年気温予測
y_test_temp = df[3287:3653, 0]
y_pred_temp = np.zeros((366,1))
i = 0
while i <= 365:
    y_pred_temp[i] = y_pred[i] + df2[i,0] # 2011~2019の平均気温にズレから算出した気温を足し合わせる
 #   print(y_pred_temp[i])
    i = i + 1
# モデル評価
print(r2_score(y_test,y_pred))

# 予測と正解のグラフ作成
p1 = plt.plot(y_test_temp)
p2 = plt.plot(y_pred_temp)
plt.title('predict air-temperature')
plt.xlabel('days from 2020/1/1 ')
plt.ylabel('mean air-temp')
plt.legend(['Actual', 'Model'], loc='upper left')
plt.savefig('predict-temp-2020-sample.png')
plt.show()
```
##4. 結果
![predict-temp-2020-all.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1470630/909e9df5-aac4-06fe-7096-0c1fa7dc9b00.png)

決定係数は0.12~0.13となり、精度としてはかなり低かった。
特に冬場において、日別の気温変動を取りきれていない。
改善点は現在、検討中である。
##5. エラーの解決策
エラーが出たので、解決策を提示する。
####・問題点1： TensorFlowをアップデートしてくれ<br>
```
ImportError: Keras requires TensorFlow 2.2 or higher. Install TensorFlow via `pip install tensorflow`
```
####・問題点1の解決策：pip3をアップデートした後に、kerasとtensorflowをアップデート
```
pip3 install --upgrade pip
pip3 install --upgrade keras
pip3 install --upgrade tensorflow
```
##6. 参考書
####詳解　ディープラ-ニング　第2版　~TensorFlow/Keras・PyTorchによる時系列データ処理~　(著：巣籠　悠輔)　
##7. 最後に
今回は、気温予測を行なった。気温に関連する変数を7つ準備し、全部使ったとしても決定係数は0.12までしか上がっていない。<br>精度向上のために、変数を増やしたり、期間によって変数の利き方を変更するなどが必要があるのかもしれない。 （変数を増やせば良いと言う問題でもないが・・・）
<br>2020年の気温以外の観測データから2020年の気温予測をしているので、厳密に言うと、気温予測では無いのかもしれない。