はじめに
これまでSciKit-learnを使って電力使用量を予測する例を何度か公開してきましたが、今回はTensorFlowを使って似たようなことをするサンプルを作ってみました。
環境構築
テスト環境
- MacBook Pro Mid 2012
- Python 3.5.1 with Anaconda 4.1.0
- TensorFlow 1.0.1
- Keras 2.1.2
Anacondaのインストール
以下のURLより、自分のPC環境に適合するものをダウンロードしてインストール
TensorFlowのインストール
以下のコマンドを実行
- CPU版
$ pip install tensorflow
- GPU版
$ pip install tensorflow-gpu
Kerasのインストール
以下のコマンドを実行
$ pip install keras
Jupyterの起動
以下のコマンドを実行
$ jupyter notebook
新しいファイルを作成して、以下のコードを実行
データ取得
電力データ
以下のURLより中国電力にて公開されている電力使用量データをダウンロード
http://www.energia.co.jp/jukyuu/download.html
※2016年度と2017年度のデータを取得
気象データ
中国電力管内にある主要都市として、岡山と広島をとりあげることとし、岡山と広島の気象データをダウンロード
※ 予測精度を向上させるために、他の主要都市の気温データを追加しても良いと思います
以下のURLより気温データをダウンロード
http://www.data.jma.go.jp/gmd/risk/obsdl/index.php
※1時間おきの気温データを電力データと同じ期間にあわせて取得
データ読込
ライブラリ読込
import pandas as pd
%matplotlib inline
電力データ
df_kw = pd.read_csv("juyo-2016.csv",encoding="Shift_JIS",skiprows=1)
df_kw["MW"] = df_kw["実績(万kW)"] * 10
df_kw["DATETIME"] = df_kw.index.map(lambda _: pd.to_datetime(df_kw.DATE[_] + " " + df_kw.TIME[_]))
# 可視化
df_kw["MW"].plot(figsize=(15,4))
気象データ
def read_temp(filename):
df_temp = pd.read_csv(filename,encoding="Shift_JIS",skiprows=4)
df_temp.columns = ["DATETIME","TEMP","品質情報","均質番号"]
df_temp.DATETIME = df_temp.DATETIME.map(lambda _: pd.to_datetime(_))
return df_temp
# 岡山
df_temp_okym = read_temp("data_okayama-2016.csv")
df_temp_okym.rename(columns = {'TEMP':'TEMP_okym'}, inplace=True)
# 広島
df_temp_hrsm = read_temp("data_hiroshima-2016.csv")
df_temp_hrsm.rename(columns = {'TEMP':'TEMP_hrsm'}, inplace=True)
# 可視化
df_temp_okym.TEMP_okym.plot(figsize=(15,4))
df_temp_hrsm.TEMP_hrsm.plot(figsize=(15,4))
データ加工
電力と気温のデータを結合
# データの複製
df = df_kw.copy()
# 岡山の気温を結合
df = df.merge(df_temp_okym,how="inner", on="DATETIME")
# 広島の気温を結合
df = df.merge(df_temp_hrsm,how="inner", on="DATETIME")
# 月、週、時間の値を個別に取得
df["MONTH"] = df.DATETIME.map(lambda _: _.month)
df["WEEK"] = df.DATETIME.map(lambda _: _.weekday())
df["HOUR"] = df.DATETIME.map(lambda _: _.hour)
欠損データの削除
# null値の削除
df = df.dropna()
One-hotエンコーディング
cols = ["MONTH","WEEK","HOUR"]
for col in cols:
df = df.join(pd.get_dummies(df[col], prefix=col))
学習
x_cols = ["TEMP_okym","TEMP_hrsm"] + df.columns.tolist()[14:]
X = df[x_cols]
y = df["MW"]
# ラベル付きデータをトレーニングセット (X_train, y_train)とテストセット (X_test,y_test)に分割
from sklearn import model_selection
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=.2, random_state=42)
# 正規化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)
# Keras読込
from keras.models import Sequential
from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasRegressor
# モデル生成用関数
def reg_model():
reg = Sequential()
reg.add(Dense(10, input_dim=len(x_cols), activation='relu'))
reg.add(Dense(16, activation='relu'))
reg.add(Dense(1))
reg.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
reg.summary()
return reg
# モデルの取得
model = KerasRegressor(build_fn=reg_model, epochs=200, batch_size=16, verbose=0)
# 学習
model.fit(X_train, y_train)
# スコア(参考値)
model.score(X_test, y_test)
検証
from sklearn.metrics import mean_squared_error
# 予測値の取得
y_pred = model.predict(X_test)
# 二乗平方根で誤差を算出
mse = mean_squared_error(y_test, y_pred)
print("KERAS REG RMSE : %.2f" % (mse ** 0.5))
print("KERAS REG SCORE: %3.2f" % (1.0 - mse ** 0.5 / y_test.mean()))
# 可視化
pd.DataFrame({"pred":y_pred, "act":y_test})[:100].reset_index(drop=True).plot(figsize=(15,4))
誤差の出力は「KERAS REG RMSE : 349.74」で、予測結果のグラフは以下のとおり。
...なんだかあってそう(^-^)
予測
2017年度データを予測し、確認する。
# 電力データを読込
df_kw = pd.read_csv("juyo-2017.csv",encoding="Shift_JIS",skiprows=1)
# 岡山のデータを読込
df_temp_okym = read_temp("data_okayama-2017.csv")
df_temp_okym.rename(columns = {'TEMP':'TEMP_okym'}, inplace=True)
# 広島のデータを読込
df_temp_hrsm = read_temp("data_hiroshima-2017.csv")
df_temp_hrsm.rename(columns = {'TEMP':'TEMP_hrsm'}, inplace=True)
# データ加工
df_kw.columns = ["DATE","TIME","万kW"]
df_kw["MW"] = df_kw["万kW"] * 10
df_kw["DATETIME"] = df_kw.index.map(lambda _: pd.to_datetime(df_kw.DATE[_] + " " + df_kw.TIME[_]))
# データ結合
df = df_kw.copy()
df = df.merge(df_temp_okym,how="inner", on="DATETIME")
df = df.merge(df_temp_hrsm,how="inner", on="DATETIME")
# 追加データ作成
df["MONTH"] = df.DATETIME.map(lambda _: _.month)
df["WEEK"] = df.DATETIME.map(lambda _: _.weekday())
df["HOUR"] = df.DATETIME.map(lambda _: _.hour)
# 欠損データ削除
df = df.dropna()
# One-hotエンコーディング
cols = ["MONTH","WEEK","HOUR"]
for col in cols:
df = df.join(pd.get_dummies(df[col], prefix=col))
# テストデータの不足分を補完
for col in x_cols[2:]:
if not col in df.columns:
df[col] = 0
# 7月の電力使用量を予測
df_pred = df[df.MONTH==7]
# 予測用データ
X = df_pred[x_cols].as_matrix().astype('float64')
y = df_pred["MW"].as_matrix().astype('int').flatten()
# 正規化
X = scaler.transform(X)
# 予測値の取得
y_pred = model.predict(X)
# 二乗平方根で誤差を算出
mse = mean_squared_error(y, y_pred)
print("KERAS REG RMSE : %.2f" % (mse ** 0.5))
# 可視化
pd.DataFrame({"pred":y_pred, "act":y}, index=df_pred.index).plot(figsize=(15,4),ylim=(4000,12000))
誤差の出力は「KERAS REG RMSE : 368.87」で、予測結果のグラフは以下のとおり。
良いかも(^-^)
参考資料