テック プログラミング

ruby で 統計・機械学習の現状とPyCall

ペパボアドベントカレンダ用の記事。とてもブログ書くの久しぶりになってしまったけれど、やっていく。

クリスマスっぽい記事を書きたかったけど、なんにも思いつかなかったので、Ruby * 機械学習のお話を書いていこうと思います。殆ど感想ともとれる記事なので、コラム程度にお読みいただければ幸いです。

機械学習の言語と言えば

機械学習をやろう!と思った人がまず最初に触れる言語は(近年は)言わずもがなPythonだと思います。多くの人はなぜPythonを使うのかわからないまま(もしくは私がそう思っているだけかもしれませんが)、Pythonによる機械学習の入門書を手に取り、numpyやmatplotlib等のライブラリを用いて学習・開発を行っていると思います。
あるいは、近い分野で統計を扱おうという人は、なんとなくRの入門書を手に取り、Rによる統計解析などを行っていると思います。

別に他の言語でもできないわけじゃない

PythonやR(以下はRについて省略します)はとても素敵な言語ですが、たまには他の言語で書きたくなることがあると思います。それは、他の言語の動作環境やライブラリに必要性を感じてのことかもしれませんし、気分を変えたいという気持ちもあるかもしれません。

もちろん、他の任意のプログラミング言語で同様の計算を行うことは出来ると思います。しかし、どうしてそれが行われていないか。その理由はコーディングの量と計算の速度・安定性に大きな理由があると思っています。

Rubyでは・・・

例えば、私がいま仕事で使っているRubyという言語にフォーカスを当ててみると、numpy の代わりになるライブラリとして、 numo, GPUで高速に処理したいというニーズには、cupy の代わりに cumoという選択肢があります。これらのライブラリを使うことで一応は科学計算や多次元行列の演算などを行うことができます。

これらのライブラリは試みとしては非常に面白く、個人的には非常に応援しているものの、学生が初学で学ぶに適しているか、実務に耐えうるか。という問に対しては首を縦に振りづらいのが正直なところです。

それはどうしてか。私自身は、numpyを初めとするpythonのライブラリ群には大学時代の研究で非常にお世話になりました。そのとき、私が躊躇せずpythonを選ぶことが出来たのはナレッジの膨大さでした。書店に行けば入門書はすべてpython, 大学の指導教官もpythonを使っている。そしてライブラリ群はすでに安定していて直面する殆どのバグは既知となっていて対処法が明らか。そのような環境が私にpythonを選ばせた訳です。私と同じように、初学で始めようとする人には他の言語で始めるよりスムーズな学びにつながると思うからです。

実務に対してはどうでしょうか。実務で使うときに重要なキーポイントは、データの信頼性、それとコストです。Rubyの科学計算ライブラリはpythonのそれらと比べて未だ幾ばくか安定性に欠けていたり、機能に欠けていたりするところがあります。その為、必然的にデータの信頼性がおちたりコストがかかりやすいRubyを用いるよりも、Pythonを用いようとするのは自然な流れだといえます。

とはいえ、気になる

とはいえ、Rubyでどのように科学計算が行われているのか気になったので、何か試しに動かせないか。と思っていたらとても良いものがありました。PyCallです。

これはPythonオブジェクトやライブラリをrubyで扱うことが出来るようになるというライブラリで、これを用いれば科学計算をRubyで行うことも期待が持てそうです。幸いにもるびま(Ruby Magazine)にぴったりの記事があったのでこちらを参考にしつつサンプルコードを動かすところまでやってみました。

PyCallで ruby with jupyter notebook

セットアップは面倒なのでdocker imageを用います。

 docker run -p 8888:8888 -it --rm --name iruby -v ~:/notebooks/local rubydata/pycall 

これだけで、  http://localhost:8888 にjupyter notebookが起動できます。

この中のサンプルコードを見てみます。

require 'matplotlib/iruby'
 Matplotlib::IRuby.activate
 require 'pycall/import'
 include PyCall::Import
 pyimport 'numpy', as: 'np'
 plt = Matplotlib::Pyplot
plt.xkcd do
   # Based on "Stove Ownership" from XKCD by Randall Monroe
   # http://xkcd.com/418/
 fig = plt.figure()
   ax = fig.add_axes(PyCall.tuple(0.1, 0.2, 0.8, 0.7))
   ax.spines['right'].set_color('none')
   ax.spines['top'].set_color('none')
   plt.xticks([])
   plt.yticks([])
   ax.set_ylim([-30, 10])
 data = np.ones.(100)
   data[PyCall.slice(70, nil)] -= np.arange.(30)
 plt.annotate(
     "THE DAY I REALIZED\nI COULD COOK BACON\nWHENEVER I WANTED",
     xy: PyCall.tuple(70, 1),
     arrowprops: { arrowstyle: '->' },
     xytext: PyCall.tuple(15, -10)
   )
 plt.plot(data)
 plt.xlabel('time')
   plt.ylabel('my overall health')
   fig.text(
     0.5, 0.05,
     '"Stove Ownership" from xkcd by Randall Monroe',
     ha: 'center'
   )
 # Based on "The Data So Far" from XKCD by Randall Monroe
   # http://xkcd.com/373/
 fig = plt.figure()
   ax = fig.add_axes(PyCall.tuple(0.1, 0.2, 0.8, 0.7))
   ax.bar([0, 1], [0, 100], 0.25)
   ax.spines['right'].set_color('none')
   ax.spines['top'].set_color('none')
   ax.xaxis.set_ticks_position('bottom')
   ax.set_xticks([0, 1])
   ax.set_xlim([-0.5, 1.5])
   ax.set_ylim([0, 110])
   ax.set_xticklabels(["CONFIRMED BY\nEXPERIMENT", "REFUTED BY\nEXPERIMENT"])
   plt.yticks([])
 plt.title("CLAIMS OF SUPERNATURAL POWERS")
 fig.text(
     0.5, 0.05,
     '"The Data So Far" from xkcd by Randall Monroe',
     ha: 'center'
   )
 end

このコードはまさしくRubyでかかれているものの、numpyやmatplotlibを用いることが出来ています。このように、純粋にRuby独力ではないものの、共存していくような仕組みも非常に重要だと思っていて、やりたいことが任意の言語で出来る環境というのはとても魅力的です。
※同等のコードをpythonでかくとこれです

まとめ

ここまでいろいろ書いてきたものの、現状RubyとPythonを比べると機械学習や科学計算、統計を行う面においてRubyは力不足感が否めず、初学者や実務には向かない。がしかし、Rubyでもそういったことやってみたいですよね。というところに対して面白いなあと思ったPyCallの取り組みについて感想を交えつつ紹介しました。

適材適所でつかっていくのももちろん重要(だしそうしないといけない局面は多々ある)ですが、同じ言語が技術領域をグローバルに使えるのも(頭脳の)切り替えコストが少なくて私は好きです。

それでは、みなさん。メリークリスマス🎄。

免責事項

この文章は筆者の所属する組織の総意や代表をする意図はなく、個人として記述されています。そのため、文責は筆者自身にあり、関係する組織とはなんら関わりはありません。記述内容については注意を払っていますが、引用・記事内容を活用される際には他の情報もご参照いただき、内容の正確性についてご自身でご確認ください。

コメントを残す

メールアドレスが公開されることはありません。必須項目には印がついています *

CAPTCHA