Python
機械学習
scikit-learn

機械学習で電力需要を予測してみる パート2

はじめに

以前、同名のタイトルで投稿してからずいぶんと日数が経過し、少し熟れてきたので再度投稿してみます。

追記

2017/12/22に以下の記事を作成したので、あわせてご参照下さい。
TensorFlowで電力使用量予測 with Keras

データ収集

電力需要

まずは東京電力のサイトから電力需要のデータをダウンロードします。

http://www.tepco.co.jp/forecast/html/download-j.html

http://www.tepco.co.jp/forecast/html/images/juyo-2016.csv
※2017/1/14現在、2016/4/1〜2016/12/31の一時間毎のデータをダウンロードできました。

また、URLを変更すると2014年のデータも入手できました。

http://www.tepco.co.jp/forecast/html/images/juyo-2014.csv
※2017/1/14現在、2015年のデータはからっぽでデータが入っていませんでした。

ダウンロードしたデータは日付、時刻、電力実績のCSVとなっています。

ちなみに以下のコマンドで取得することもできそうです。

$ curl -O http://www.tepco.co.jp/forecast/html/images/juyo-2014.csv
$ curl -O http://www.tepco.co.jp/forecast/html/images/juyo-2016.csv

気温

前回同様に、気象庁から過去の気象データをダウンロードします。

http://www.data.jma.go.jp/gmd/risk/obsdl/index.php

地点は「東京」、項目は「時別値」「気温」、期間は2013/12/31〜2015/1/1と2015/12/31〜2017/1/1とし、data-2014.csv、data-2016.csvという名前で保存します。
ここで、少し長めの期間を選択しているのは、後で期間を絞って取り込むためです。

ダウンロードしたデータは日時、気温、品質情報、均質番号というデータの入ったCSVです。

ちなみにこれは普通にサイトからダウンロードするのが早そうです。

データ読込

ライブラリ

import pandas as pd
import numpy as np
import datetime as dt
import math

電力需要

まず、2014年の電力データを読み込みます。

filename = "juyo-2014.csv"

# 文字コードがシフトJISで、不要な行を飛ばして読み込む
df = pd.read_csv(filename,encoding="SHIFT-JIS",skiprows=2)

# 列名を変換
df.columns = ["DATE","TIME","KW"]

# 日付と時間のデータが分かれているので、一つにつなげて日時型に変換し、インデックスに指定
df.index = df.index.map(lambda x: dt.datetime.strptime(df.loc[x].DATE + " " + df.loc[x].TIME,"%Y/%m/%d %H:%M"))

# 月データの取得
df["MONTH"] = df.index.month

# 曜日データの取得
df["WEEK"] = df.index.weekday

# 時間データの取得
df["HOUR"] = df.index.hour

df_kw = df

気温

次に、2014年の気温データを読み込みます。

filename = "data-2014.csv"

# 文字コードがシフトJISで、不要な行を飛ばし、必要な2列のみ取得
df = pd.read_csv(filename,encoding="SHIFT-JIS",skiprows=4)[[0,1]]

# 列名を変換
df.columns = ["DATE","TEMP"]

# 日時データを日時型に変換してインデックスに指定
df.index = df.index.map(lambda x: dt.datetime.strptime(df.loc[x].DATE,"%Y/%m/%d %H:%M:%S"))

df_temp = df

電力需要と気温のデータを結合

d1 = df_kw.index.min()
d2 = df_kw.index.max()

df_kw["TEMP"] = df_temp.ix[d1:d2].TEMP

データの加工

機械学習に用いる入力データと出力データを取得します。
予測するのは電力需要なので、出力はKW列、入力はMONTH、WEEK、HOUR、TEMP列とします。

# 入力に使用するデータ列の指定
X_cols = ["MONTH","WEEK","HOUR","TEMP"]

# 出力に使用するデータ列の指定
y_cols = ["KW"]

# 入力・出力データの取得
X = df_kw[X_cols].as_matrix().astype('float')
y = df_kw[y_cols].as_matrix().astype('int').flatten()

学習データと検証データに分割します。

from sklearn import cross_validation

X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=.1, 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)

学習

回帰モデルで学習します。

from sklearn.ensemble import RandomForestRegressor

model = RandomForestRegressor()
model.fit(X_train, y_train)

予測

分割したテストデータを使ってスコアを計算します。

print(model.score(X_test,y_test))

スコアは「0.91601162513664502」でした(^-^)

予測結果の確認

予測結果と実データをグラフ化し、確認してみます。

# 予測結果
result = model.predict(X_test)

# データフレームに変換
df_result = pd.DataFrame({
    "y_test":y_test,
    "result":result
})

# グラフライブラリ
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt

# グラフ描画
df_result.plot(figsize=(15, 3))

Unknown.png

当たってるようなんだけど、どうなのかいまいちよくわからない。

データ数を減らして再確認。

# グラフ描画
df_result[:20].plot(figsize=(15, 3))

Unknown.png

いい感じじゃないですか!

2016年のデータを使って予測

データ読込

2014年のデータと同じ手順で2016年のデータを読み込みます。

# 電力需要
filename = "juyo-2016.csv"

df = pd.read_csv(filename,encoding="SHIFT-JIS",skiprows=2)
df.columns = ["DATE","TIME","KW"]
df.index = df.index.map(lambda x: dt.datetime.strptime(df.loc[x].DATE + " " + df.loc[x].TIME,"%Y/%m/%d %H:%M"))
df["MONTH"] = df.index.month
df["WEEK"] = df.index.weekday
df["HOUR"] = df.index.hour

# 4月分に限定して利用
df_kw = df[df.index.month == 4]

# 気温
filename = "data-2016.csv"

df = pd.read_csv(filename,encoding="SHIFT-JIS",skiprows=4)[[0,1]]
df.columns = ["DATE","TEMP"]
df.index = df.index.map(lambda x: dt.datetime.strptime(df.loc[x].DATE,"%Y/%m/%d %H:%M:%S"))

df_temp = df

# データ結合
d1 = df_kw.index.min()
d2 = df_kw.index.max()
df_kw["TEMP"] = df_temp.ix[d1:d2].TEMP

データ加工

# 入力・出力データの取得
X = df_kw[X_cols].as_matrix().astype('float')
y = df_kw[y_cols].as_matrix().astype('int').flatten()

X_test = scaler.transform(X)
y_test = y

予測

2014年のデータで学習したモデルを使用して予測し、スコアを計算します。

model.score(X_test,y_test)

結果は、少し落ちて「0.82435418225963963」でした。

予測結果の確認

# 予測結果
result = model.predict(X_test)

# データフレームに変換
df_result = pd.DataFrame({
    "y_test":y_test,
    "result":result
})

# グラフ描画
df_result.plot(figsize=(15, 3))

Unknown.png

もう少し工夫が必要ですね(-_-;)