晴耕雨読オンライン

おたくエンジニアが日々の所感を備忘録代わりにつらつら書いていくブログです。

機械学習を使って明日の気温を予測してみる

 

 

 

 

機械学習で明日の気温をざっくり予想できたら面白そうだなと思って ちょっと作ってみました。

アンサンブルとかディープとかそういうのは一切ないです。

自分の備忘録も兼ねて。

 

In [1]:
#import
import numpy as np
import pandas as pd
import os
import csv
import datetime
import matplotlib.pyplot as plt
%matplotlib inline


from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import make_scorer
from sklearn.metrics import r2_score
 

天候データは気象庁からダウンロードしましょう https://www.data.jma.go.jp/gmd/risk/obsdl/index.php

In [2]:
#データを読む
os.chdir("~/data")

df=pd.DataFrame()
df_org=pd.read_csv("data.csv",encoding="shiftjis",header=2).drop([0,1],axis=0).reset_index(drop=True)
df["datetime"]=pd.to_datetime(df_org["年月日"])
df["Max_temp"]=df_org["最高気温(℃)"]
df["Min_temp"]=df_org["最低気温(℃)"]
df=df.set_index("datetime",drop=True)
 

過去一週間の気温の推移をざっくりとDataFrameにぶちこみます

In [3]:
def week_dataset(df):
    tmp=np.zeros((2,8,len(df)))
    for i in range(1,8):
        for j in range(len(df)):
            tmp[0][i][j]=df.Max_temp.iloc[j-i]
            tmp[1][i][j]=df.Min_temp.iloc[j-i]
        df[str("Max -")+str(i)]=tmp[0][i]
        df[str("Min -")+str(i)]=tmp[1][i]
    return df
        
df=week_dataset(df)
        
df.head()
Out[3]:
 
  Max_temp Min_temp Max -1 Min -1 Max -2 Min -2 Max -3 Min -3 Max -4 Min -4 Max -5 Min -5 Max -6 Min -6 Max -7 Min -7
datetime                                
2011-01-01 10.7 -3.0 5.6 0.2 11.6 0.1 10.3 -2.3 9.5 -3.9 9.2 -1.3 13.9 0.9 15.6 4.5
2011-01-02 11.4 -0.6 10.7 -3.0 5.6 0.2 11.6 0.1 10.3 -2.3 9.5 -3.9 9.2 -1.3 13.9 0.9
2011-01-03 9.3 -1.0 11.4 -0.6 10.7 -3.0 5.6 0.2 11.6 0.1 10.3 -2.3 9.5 -3.9 9.2 -1.3
2011-01-04 10.0 0.0 9.3 -1.0 11.4 -0.6 10.7 -3.0 5.6 0.2 11.6 0.1 10.3 -2.3 9.5 -3.9
2011-01-05 11.1 -2.6 10.0 0.0 9.3 -1.0 11.4 -0.6 10.7 -3.0 5.6 0.2 11.6 0.1 10.3 -2.3
 

Max-1というのは、一日前の最高気温を表します。 Min-6だったら、6日前の最低気温を表しています。

In [4]:
X=df.drop(["Max_temp","Min_temp"],axis=1)
Y_Max=df["Max_temp"]
Y_Min=df["Min_temp"]

X_train=X[:-365]
X_test=X[-365:]
Y_Max_train=Y_Max[:-365]
Y_Max_test=Y_Max[-365:]
Y_Min_train=Y_Min[:-365]
Y_Min_test=Y_Min[-365:]

X_train.head()
Out[4]:
 
  Max -1 Min -1 Max -2 Min -2 Max -3 Min -3 Max -4 Min -4 Max -5 Min -5 Max -6 Min -6 Max -7 Min -7
datetime                            
2011-01-01 5.6 0.2 11.6 0.1 10.3 -2.3 9.5 -3.9 9.2 -1.3 13.9 0.9 15.6 4.5
2011-01-02 10.7 -3.0 5.6 0.2 11.6 0.1 10.3 -2.3 9.5 -3.9 9.2 -1.3 13.9 0.9
2011-01-03 11.4 -0.6 10.7 -3.0 5.6 0.2 11.6 0.1 10.3 -2.3 9.5 -3.9 9.2 -1.3
2011-01-04 9.3 -1.0 11.4 -0.6 10.7 -3.0 5.6 0.2 11.6 0.1 10.3 -2.3 9.5 -3.9
2011-01-05 10.0 0.0 9.3 -1.0 11.4 -0.6 10.7 -3.0 5.6 0.2 11.6 0.1 10.3 -2.3
 

XとYに分けます。Yには当日の最低気温と最高気温をそれぞれ切り出します。

Xには一日前までの時点での7日間の気温の推移が詰まりますね。

In [5]:
forest_Max = RandomForestRegressor(min_samples_leaf=3, random_state=0)
forest_Max.fit(X_train, Y_Max_train)
forest_Min = RandomForestRegressor(min_samples_leaf=3, random_state=0)
forest_Min.fit(X_train, Y_Min_train)
Out[5]:
RandomForestRegressor(bootstrap=True, criterion='mse', max_depth=None,
           max_features='auto', max_leaf_nodes=None,
           min_impurity_decrease=0.0, min_impurity_split=None,
           min_samples_leaf=3, min_samples_split=2,
           min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
           oob_score=False, random_state=0, verbose=0, warm_start=False)
 

お手軽神ツールRandomForestRegressorを使ってモデルを作ります

In [6]:
print("MaxTemp score",forest_Max.score(X_train, Y_Max_train))
print("MinTemp score",forest_Min.score(X_train, Y_Min_train))
 
MaxTemp score 0.9573943473669106
MinTemp score 0.9837380953120993
 

モデルのフィッティングスコアを見てみると最高気温が0.95で最低気温が0.98です。おおむね満足な数値と言えましょう。

最高気温より最低気温のほうが表現しやすいようですね。だから何かってわけではないですが。

In [7]:
Y_Max_pred=forest_Max.predict(X_test)
Y_Min_pred=forest_Min.predict(X_test)
 

お手軽神ツールRandomForestRegressorで予想します。

In [8]:
result=pd.DataFrame([Y_Max_pred,Y_Min_pred],index=["MaxTemp_pred","MinTemp_pred"]).T
result.index=X_test.index
result["MaxTemp_act"]=Y_Max_test
result["MinTemp_act"]=Y_Min_test
 

結果を整理。

In [9]:
result.plot(figsize=(16,6))
Out[9]:
<matplotlib.axes._subplots.AxesSubplot at 0x1e899802400>
 
 

XX_predが予測値、XX_actが実測値です。

一日前のデータから翌日の気温を予測するのは、結構いい感じに行けそうですね。

In [10]:
print("MaxTemp pred r2score",r2_score(Y_Max_test, Y_Max_pred))
print("MinTemp pred r2score",r2_score(Y_Min_test, Y_Min_pred))
 
MaxTemp pred r2score 0.8336991228198057
MinTemp pred r2score 0.9558456419510862
 

決定係数を使って精度を見ると、最高気温は0.83で最低気温は0.95でした。

最高気温は結構幅があるので外しやすいんでしょうかね。

 

じゃあ次、明日を予測してみましょう。

気象庁のサイトから直近のデータを持ってきます。

1/26までしかなかったので、このデータから本日1/27の予測を行ってみます。

これで結果が妥当かどうか見てみます。

In [11]:
df_pred=pd.DataFrame()
dfp=pd.read_csv("data2.csv",encoding="shiftjis",header=3).drop([0,1],axis=0).reset_index(drop=True)
df_pred["datetime"]=pd.to_datetime(dfp["年月日"])
df_pred["Max_temp"]=dfp["最高気温(℃)"]
df_pred["Min_temp"]=dfp["最低気温(℃)"]
df_pred=df_pred.set_index("datetime",drop=True)
 

DataFrameを作ります

In [12]:
df_pred=week_dataset(df_pred)
df_pred.iloc[-1:]
Out[12]:
 
  Max_temp Min_temp Max -1 Min -1 Max -2 Min -2 Max -3 Min -3 Max -4 Min -4 Max -5 Min -5 Max -6 Min -6 Max -7 Min -7
datetime                                
2019-01-26 9.4 -1.0 9.4 -1.8 10.6 2.5 11.6 -2.1 10.7 -3.3 10.3 -1.3 12.5 -1.6 11.8 -1.3
 

26日までしかないので、今日のデータを作ってあげる必要があります。

In [13]:
pred=pd.DataFrame()
pred["datetime"]=pd.to_datetime(["2019-01-27"])
pred.index=pred.datetime
pred=pred.drop("datetime",axis=1)

pred["Max -1"]=df_pred.iloc[-1]["Max_temp"]       
pred["Min -1"]=df_pred.iloc[-1]["Min_temp"]
                          
for i in range(2,8):
    pred["Max -"+str(i)]=df_pred.iloc[-1]["Max -"+str(i-1)]
    pred["Min -"+str(i)]=df_pred.iloc[-1]["Min -"+str(i-1)]
In [14]:
pred
Out[14]:
 
  Max -1 Min -1 Max -2 Min -2 Max -3 Min -3 Max -4 Min -4 Max -5 Min -5 Max -6 Min -6 Max -7 Min -7
datetime                            
2019-01-27 9.4 -1.0 9.4 -1.8 10.6 2.5 11.6 -2.1 10.7 -3.3 10.3 -1.3 12.5 -1.6
 

今日のXができました。

In [15]:
Y_Max_pred=forest_Max.predict(pred)
Y_Min_pred=forest_Min.predict(pred)
In [16]:
print("Max temp",Y_Max_pred)
print("Min temp",Y_Min_pred)
 
Max temp [11.14383333]
Min temp [-1.28191667]
 

さて、予測したところ、1/27の最高気温は11.1度、最低気温は-1.3度のようです。

使用した地点は府中市なので、この天気予報を参照すると・・・

 

f:id:Narow613:20190127174921p:plain

最高気温はピタリ賞です。

ただ、最低気温が1度ほどずれていますね。うーん惜しい。

 

 

以上、予測してみたコーナーでした。