PyCallを使ってRubyで電力需要予測をしてみる

ライブラリ読込

日付と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]:
# 入力・出力に使用するデータ列の指定
x_cols = ["MONTH","WEEK","HOUR"]
y_cols = ["KW"]
nil
In [7]:
# 入力・出力データの取得
x = df[x_cols].as_matrix.().astype.("float")
y = df[y_cols].as_matrix.().astype.("int").flatten.()
nil
In [8]:
# データ分割
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 [9]:
# 正規化
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 [10]:
# 学習
pyfrom 'sklearn.ensemble', import: :RandomForestRegressor

model = RandomForestRegressor.()
model.fit.(x_train, y_train)
Out[10]:
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 [11]:
# スコア計算
model.score.(x_test,y_test)
Out[11]:
0.6996302546161193
In [12]:
# 検証
result = model.predict.(x_test)
nil
In [13]:
# テストデータと予測結果の比較
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[13]:
In [14]:
# 正規化と学習
scaler.fit.(x)

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

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)

予測

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

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

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

df.head.()
Out[15]:
       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 [16]:
# データ加工
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[16]:
       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 [17]:
# 入力・出力データの取得
x = df[x_cols].as_matrix.().astype.("float")
y = df[y_cols].as_matrix.().astype.("int").flatten.()

nil
In [18]:
# 正規化
x_test = scaler.transform.(x)
y_test = y
nil
In [19]:
# スコア計算
model.score.(x_test,y_test)
Out[19]:
0.7682668882076696
In [20]:
# 予測
result = model.predict.(x_test)
nil
In [21]:
# テストデータと予測結果の比較
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[21]: