PyCallを使ってRubyで電力需要予測をしてみるwith気温データ

ライブラリ読込

日付とPyCallおよび関連ライブラリを読み込みます。

In [1]:
require 'date'
require 'pycall/import'
include PyCall::Import
Out[1]:
Object
In [2]:
pyimport 'numpy', as: 'np'
pyimport 'pandas', as: 'pd'
Out[2]:
:pd

学習

2014年のデータで学習させます。

In [3]:
# データ読込
filename = "juyo-2014.csv"

df = pd.read_csv.(filename, encoding: "SHIFT-JIS", skiprows: 2)
df["KW"] = df.pop.("実績(万kW)")

df.head.()
Out[3]:
       DATE  TIME    KW
0  2014/1/1  0:00  2826
1  2014/1/1  1:00  2681
2  2014/1/1  2:00  2558
3  2014/1/1  3:00  2455
4  2014/1/1  4:00  2396
In [4]:
# データ加工
ymd = []
month = []
wday = []
hour = []

(0..PyCall.len(df)-1).each do |i|
  
  dt = Date.parse(df.DATE.ix[i])
  
  ymd << dt
  month << dt.month
  wday << dt.wday
  hour << df["TIME"].ix[i].split(":")[0]
  
end

df["HOUR"] = hour
df["MONTH"] = month
df["WEEK"] = wday

df.head.()
Out[4]:
       DATE  TIME    KW HOUR  MONTH  WEEK
0  2014/1/1  0:00  2826    0      1     3
1  2014/1/1  1:00  2681    1      1     3
2  2014/1/1  2:00  2558    2      1     3
3  2014/1/1  3:00  2455    3      1     3
4  2014/1/1  4:00  2396    4      1     3
In [5]:
# グラフでデータを確認
pyimport 'matplotlib.pyplot', as: 'plt'

plt.figure.(figsize: PyCall.tuple(10, 3))

plt.xlim.(100,400)
plt.plot.(df.KW, label: "KW")

plt.legend.()

# グラフを画像として保存
plt.savefig.("pycall.svg")
plt.close.()

# 保存されたグラフの画像を読み込む
open("pycall.svg")
Out[5]:
In [6]:
# 気温データ読込
filename = "data-2014.csv"

df_temp = pd.read_csv.(filename, encoding: "SHIFT-JIS", skiprows: 4)[[0,1]]
df_temp["DATETIME"] = df_temp.pop.("Unnamed: 0")
df_temp["TEMP"] = df_temp.pop.("Unnamed: 1")
df_temp.head.()
Out[6]:
             DATETIME  TEMP
0  2013/12/31 1:00:00   2.6
1  2013/12/31 2:00:00   2.8
2  2013/12/31 3:00:00   2.1
3  2013/12/31 4:00:00   2.0
4  2013/12/31 5:00:00   2.4
In [7]:
# 一時間前の気温を入手

ymd = []
temp = []

(0..PyCall.len(df)-1).each do |i|
  
  ymd << df_temp.DATETIME.ix[i + 22]
  temp << df_temp.TEMP.ix[i + 22]
  
end
nil
In [8]:
# グラフでデータを確認
#pyimport 'matplotlib.pyplot', as: 'plt'

plt.figure.(figsize: PyCall.tuple(10, 3))

plt.xlim.(100,400)
plt.plot.(temp, label: "Degree")

plt.legend.()

# グラフを画像として保存
plt.savefig.("pycall.svg")
plt.close.()

# 保存されたグラフの画像を読み込む
open("pycall.svg")
Out[8]:
In [9]:
# 気温データの追加
df["DATETIME"] = ymd
df["TEMP"] = temp
df.tail.()
Out[9]:
            DATE   TIME    KW HOUR  MONTH  WEEK             DATETIME  TEMP
8755  2014/12/31  19:00  3147   19     12     3  2014/12/31 18:00:00  10.7
8756  2014/12/31  20:00  3079   20     12     3  2014/12/31 19:00:00  10.6
8757  2014/12/31  21:00  2982   21     12     3  2014/12/31 20:00:00  10.2
8758  2014/12/31  22:00  2864   22     12     3  2014/12/31 21:00:00   9.0
8759  2014/12/31  23:00  2806   23     12     3  2014/12/31 22:00:00   8.8
In [10]:
# 入力・出力に使用するデータ列の指定
x_cols = ["MONTH","WEEK","HOUR","TEMP"]
y_cols = ["KW"]
nil
In [11]:
# 入力・出力データの取得
x = df[x_cols].as_matrix.().astype.("float")
y = df[y_cols].as_matrix.().astype.("int").flatten.()
nil
In [12]:
# データ分割
pyfrom 'sklearn.cross_validation', import: :train_test_split

x_train, x_test, y_train, y_test = train_test_split.(x, y, test_size: 0.1)
nil
In [13]:
# 正規化
pyfrom 'sklearn.preprocessing', import: :StandardScaler

scaler = StandardScaler.()
scaler.fit.(x_train)

x_train = scaler.transform.(x_train)
x_test = scaler.transform.(x_test)
nil
In [14]:
# 学習
pyfrom 'sklearn.ensemble', import: :RandomForestRegressor

model = RandomForestRegressor.()
model.fit.(x_train, y_train)
Out[14]:
RandomForestRegressor(bootstrap=True, criterion='mse', max_depth=None,
           max_features='auto', max_leaf_nodes=None,
           min_impurity_split=1e-07, min_samples_leaf=1,
           min_samples_split=2, min_weight_fraction_leaf=0.0,
           n_estimators=10, n_jobs=1, oob_score=False, random_state=None,
           verbose=0, warm_start=False)
In [15]:
# スコア計算
model.score.(x_test,y_test)
Out[15]:
0.92810532242631
In [16]:
# 検証
result = model.predict.(x_test)
nil
In [17]:
# テストデータと予測結果の比較
plt.figure.(figsize: PyCall.tuple(10, 3))

plt.title.("y_test and result")
plt.xlim.(0,100)

plt.plot.(y_test, label: "y_test")
plt.plot.(result, label: "result")

plt.legend.()

# グラフを画像として保存
plt.savefig.("pycall.svg")
plt.close.()

# 保存されたグラフの画像を読み込む
open("pycall.svg")
Out[17]:
In [18]:
# 全データを対象とした正規化と学習
scaler.fit.(x)

x_train = scaler.transform.(x)
y_train = y

model.fit.(x_train, y_train)
Out[18]:
RandomForestRegressor(bootstrap=True, criterion='mse', max_depth=None,
           max_features='auto', max_leaf_nodes=None,
           min_impurity_split=1e-07, min_samples_leaf=1,
           min_samples_split=2, min_weight_fraction_leaf=0.0,
           n_estimators=10, n_jobs=1, oob_score=False, random_state=None,
           verbose=0, warm_start=False)

予測

電力需要の予測値を2016年のデータを比較してみます。

In [19]:
# データ読込
filename = "juyo-2016.csv"

df = pd.read_csv.(filename, encoding: "SHIFT-JIS", skiprows: 2)
df["KW"] = df.pop.("実績(万kW)")

df.head.()
Out[19]:
       DATE  TIME    KW
0  2016/4/1  0:00  2555
1  2016/4/1  1:00  2433
2  2016/4/1  2:00  2393
3  2016/4/1  3:00  2375
4  2016/4/1  4:00  2390
In [20]:
# データ加工
ymd = []
month = []
wday = []
hour = []

(0..PyCall.len(df)-1).each do |i|
  
  dt = Date.parse(df.DATE.ix[i])
  
  month << dt.month
  wday << dt.wday
  hour << df["TIME"].ix[i].split(":")[0]
  
end

df["HOUR"] = hour
df["MONTH"] = month
df["WEEK"] = wday

df.head.()
Out[20]:
       DATE  TIME    KW HOUR  MONTH  WEEK
0  2016/4/1  0:00  2555    0      4     5
1  2016/4/1  1:00  2433    1      4     5
2  2016/4/1  2:00  2393    2      4     5
3  2016/4/1  3:00  2375    3      4     5
4  2016/4/1  4:00  2390    4      4     5
In [21]:
# 気温データ読込
filename = "data-2016.csv"

df_temp = pd.read_csv.(filename, encoding: "SHIFT-JIS", skiprows: 4)[[0,1]]
df_temp["DATETIME"] = df_temp.pop.("Unnamed: 0")
df_temp["TEMP"] = df_temp.pop.("Unnamed: 1")
df_temp.head.()
Out[21]:
             DATETIME  TEMP
0  2015/12/31 1:00:00   5.9
1  2015/12/31 2:00:00   4.6
2  2015/12/31 3:00:00   4.3
3  2015/12/31 4:00:00   3.6
4  2015/12/31 5:00:00   3.6
In [22]:
# 一時間前の気温を入手

ymd = []
temp = []

skip = 24 * 92 - 2

(0..PyCall.len(df)-1).each do |i|
  
  ymd << df_temp.DATETIME.ix[i + skip]
  temp << df_temp.TEMP.ix[i + skip]
  
end
nil
In [23]:
# 気温データの追加
df["DATETIME"] = ymd
df["TEMP"] = temp
df.tail.()
Out[23]:
            DATE   TIME    KW HOUR  MONTH  WEEK             DATETIME  TEMP
6595  2016/12/31  19:00  3259   19     12     6  2016/12/31 18:00:00   7.2
6596  2016/12/31  20:00  3205   20     12     6  2016/12/31 19:00:00   6.5
6597  2016/12/31  21:00  3108   21     12     6  2016/12/31 20:00:00   5.8
6598  2016/12/31  22:00  2994   22     12     6  2016/12/31 21:00:00   6.1
6599  2016/12/31  23:00  2946   23     12     6  2016/12/31 22:00:00   5.4
In [24]:
# 入力・出力データの取得
x = df[x_cols].as_matrix.().astype.("float")
y = df[y_cols].as_matrix.().astype.("int").flatten.()
nil
In [25]:
# 正規化
x_test = scaler.transform.(x)
y_test = y
nil
In [26]:
# スコア計算
model.score.(x_test,y_test)
Out[26]:
0.8350566594143941
In [27]:
# 予測
result = model.predict.(x_test)
nil
In [31]:
# テストデータと予測結果の比較
plt.figure.(figsize: PyCall.tuple(10, 3))

plt.title.("y_test and result")
plt.xlim.(100,400)

plt.plot.(y_test, label: "y_test")
plt.plot.(result, label: "result")

plt.legend.()

# グラフを画像として保存
plt.savefig.("pycall.svg")
plt.close.()

# 保存されたグラフの画像を読み込む
open("pycall.svg")
Out[31]:
In [ ]: