PyCallを使ってRubyからPythonのライブラリを使い倒す

More than 1 year has passed since last update.


はじめに

これまで何度か紹介してきたPyCallですが、バージョンが1.0になって大幅にライブラリが変更されたので、新しいバージョンにあわせた使い方を紹介してみます。

mrkn/pycall.rb: Calling Python functions from the Ruby language


インストール

以下のコマンドでインストールができます。

gem install pycall

ちなみに、以下のライブラリも入れておくと便利です。

gem install numpy

gem install pandas


Anacondaを使っている場合

私はMacにAnaconda3-4.3.1をインストールしており、この環境では以下の環境設定をしないとエラーが出たので補足します。

export PYTHONPATH=/Users/xxx/.pyenv/versions/anaconda3-4.3.1/lib/python3.6/:/Users/xxx/.pyenv/versions/anaconda3-4.3.1/lib/python3.6/site-packages/:/Users/xxx/.pyenv/versions/anaconda3-4.3.1/lib/python3.6/lib-dynload/

export PYTHONHOME=$PYTHONPATH

※「xxx」は各自のユーザー名に置き換えて下さい。

ちなみに、anacondaというブランチで修正版が公開されているので、あわせてご参照下さい。

https://github.com/mrkn/pycall.rb/tree/anaconda


基本

PyCallを呼び出して、RubyにPythonのライブラリを設定します。

以下は、Pythonのsysを呼び出して、パスを表示するサンプルです。

require 'pycall'

sys = PyCall.import_module('sys')
p sys.path

私の環境では以下のように表示されます。

['/Users/xxx/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/pycall-1.0.2/lib/pycall/python', '/Users/xxx/.pyenv/versions/anaconda3-4.3.1/lib/python36.zip', '/Users/xxx/.pyenv/versions/anaconda3-4.3.1/lib/python3.6', '/Users/xxx/.pyenv/versions/anaconda3-4.3.1/lib/python3.6/lib-dynload', '/Users/xxx/.pyenv/versions/anaconda3-4.3.1/lib/python3.6/site-packages', '/Users/xxx/.pyenv/versions/anaconda3-4.3.1/lib/python3.6/site-packages/Sphinx-1.5.1-py3.6.egg', '/Users/xxx/.pyenv/versions/anaconda3-4.3.1/lib/python3.6/site-packages/aeosa', '/Users/xxx/.pyenv/versions/anaconda3-4.3.1/lib/python3.6/site-packages/dlib-19.6.0-py3.6-macosx-10.7-x86_64.egg']

基本的には、以下の使い方になるようです。

ライブラリ名 = PyCall.import_module('ライブラリ名')

ライブラリ名.メソッド


Numpy

Numpyは専用にgemが作ってあり、もっと使いやすくなっています。

require 'numpy'

np = Numpy
x = np.asarray([1,2,3,4,5])
p x.sum()

上記のコードを実行すると「15」が返ってくるはずです。


Pandas

Pandasにも同様に専用のgemがあります。

ここでは、以下のCSVファイルを読み込む例を紹介します。


sample.csv

a,b,c

0,1,2
3,4,5
6,7,8

以下のコードを実行します。

require 'pandas'

pd = Pandas
x = pd.read_csv('sample.csv')
p x.shape

結果、「(3, 3)」と表示されまるはずです。


Matplotlib

可視化ライブラリを使用して、とても単純なグラフを描画してみます。

require 'pycall'

plt = PyCall.import_module('matplotlib.pyplot')

plt.plot([1,3,2,4])
plt.savefig("test.png")

実行すると「test.png」という画像ファイルが生成され、以下のようなグラフが描画されます。

test.png


機械学習

毎度のことではありますが、中国電力さんが公開されている電力使用量の過去データを学習し、電力使用量を予測する機械学習のサンプルを以下に示します。

ここでは、サンプルを単純にするため、2016年度のデータのみを使って学習しています。

まずは、以下のURLより2016年度のデータをダウンロードします。

http://www.energia.co.jp/jukyuu/download.html

次に以下のサンプルを実行して下さい。

# ライブラリ読込

require 'pycall'
require 'pandas'
require 'time'

pd = Pandas

# ファイル読込
filename = "juyo-2016.csv"
df_kw = pd.read_csv(filename, encoding: "SHIFT-JIS", skiprows: 2)
df_kw["KW"] = df_kw.pop("実績(万kW)")

# データ加工
year = []
month = []
day = []
wday = []
hour = []

PyCall.len(df_kw).times do |i|

dt = DateTime.parse(df_kw.DATE.iloc[i] + " " + df_kw.TIME.iloc[i])

year << dt.year
month << dt.month
day << dt.day
wday << dt.wday
hour << dt.hour

end

df_kw["YEAR"] = year
df_kw["MONTH"] = month
df_kw["DAY"] = day
df_kw["WEEK"] = wday
df_kw["HOUR"] = hour

# 学習データの取得
cols = ["KW","YEAR","MONTH","WEEK","HOUR"]
df = df_kw[cols]
y = df.pop("KW").as_matrix().astype("int").flatten()
x = df.as_matrix().astype("float")

# クロスバリデーション
cv = PyCall.import_module('sklearn.model_selection')
x_train, x_test, y_train, y_test = cv.train_test_split(x, y, test_size: 0.1, random_state: 42)

# 正規化
preprocessing = PyCall.import_module('sklearn.preprocessing')
scaler = preprocessing.StandardScaler.new()
scaler.fit(x_train)
x_train = scaler.transform(x_train)
x_test = scaler.transform(x_test)

# 学習
ensemble = PyCall.import_module('sklearn.ensemble')
model = ensemble.RandomForestRegressor.new(random_state: 42)
model.fit(x_train, y_train)

puts model.score(x_test,y_test)

実行すると「0.77093639126251379」と表示され、約77%の精度で予測できることがわかります。


さいごに

これからもっとサンプルができたら都度追加していきます。


補足

iRuby Notebookを使うともっと色々なことができます。興味のある方は以下のURLをご参照頂き、iRubyをインストールしてご利用下さい。

Mac

http://qiita.com/mix_dvd/items/88c9c935c1c0a388ee83

Windows

http://qiita.com/mix_dvd/items/3e4305d31e7a6785fbb0