書いた人 : mrkn さん
この記事では、著者が開発中の PyCall と呼ばれる Ruby-Python ブリッジライブラリを紹介します (RubyKaigi 2016、RubyWorld Conference 2016、Ruby Business Users Conference 2017 で著者が行った講演をるびま向けにまとめました)。
みなさんは Ruby を使って機械学習や統計分析をやろうとしたことはありますか?
そのような経験がある方も、経験はないけどやってみようとしたことがある方も、誰もが「Ruby では不可能だ」と思ったことでしょう。 なぜ Ruby で機械学習はできないのでしょうか。
その大きな理由は次の 3 つです: (1) 使える道具がない、(2) やっている人がいない、(3) 作ろうとする人がいない。
現在 Ruby には、機械学習や統計分析の仕事において実用的に使える道具がありません。
なんてことを言うと「daru とか numo-narray とかあるじゃないか」と怒られるかもしれませんね。でも、daru や numo-narray などの既存の gem をいくら組み合わせても、機械学習や統計分析の仕事を現実的な効率と品質でやっていくことは不可能です。ですから、私は現在の Ruby には機械学習や統計分析のために使える道具は存在しないと考えています。
既存の gem を駆使して仕事をしようとすると、必要な機能が足りず、他の gem との連携が不十分であり、かなりの頑張りを要求されることになります。
既存の gem はオープンソースソフトウェアなので、プルリクエストを送って少しずつ実用的なものにしていけば良いと考える人がいるかもしれません。 そのような行動を取れる人はそうすれば良いのですが、仕事で機械学習や統計分析をやる必要がある多くの人にとって、主目的は「道具を作ること」ではありません。 多くの人の主目的は「まともな道具を使って仕事を完了させること」です。
さらに、機械学習や統計分析においては、道具を使う場合と作る場合とで、要求されるスキルセットが大きく違う問題があります。 そのため、道具を使う側の人間が必ずしも実用的な道具を実装できるわけでは無いのです。
既存の gem は「品質が信用できない」という問題も抱えています。この問題の最も大きな要因は次節で述べる「Ruby でやっている人がいない」ことです。 利用者が少ないので利用例も乏しくなり、公開されている情報も皆無です。 そして、このようなライブラリの多くは開発が継続していないことが多いです。
このような状況ではライブラリを全く信用できないため、利用時に実装を精読して問題がないかどうか実験を通して調査する必要があります。 でも、どうせ実装を読んだり実験したりする時間を取るなら、誰も使ってないライブラリではなく、世界中の人が使っている pandas や scikit-learn を対象とする方が良いと思いませんか?
Ruby で機械学習や統計分析をやっている人がいない理由は大きく 3 つあると私は考えています。その 1 つは前節で述べた「使える道具がない」ことです。 残りの 2 つは労働市場に関する要因で、相互に関係しています。それは「Python や R を使っている人が多い」ことと、「Python や R の求人が多い」ことです。
機械学習や統計分析においては、Python と R は無くてはならないプログラミング言語です。 この 2 言語については、多くの専門家が道具を開発していますし、信頼できる書籍も多く、Web 上の日本語の情報源も豊富に存在しています。 Python や R を使っている人が多くなるのは当然のように思えます。
そして、機械学習や統計分析の分野で活躍できるデータサイエンティストを雇用したい企業は、Python や R の能力者を募集しています。 なぜなら、Python と R がこの分野の標準的なプログラミング言語ですし、まともに仕事をするためにこの 2 言語を扱えることが最低条件だからです。 この 2 言語を要求する求人が多いことは、この 2 言語の利用者を増やす要因にもなりますから、さらに利用者が増える循環が作られています。
このような状況ですから、Ruby で機械学習や統計分析を頑張ってやろうとする人なんて現れません。
Ruby で機械学習や統計分析ができない最後の理由は「道具を作ろうとする人がいない」です。
前 2 節の繰り返しになりますが、この分野においては道具を作ることが目的の人が少なく、しかも使われないものを作りたい人も少ないでしょう。 しかし、「自分で使うため」とか、「自分で作って学ぶため」などの理由で、あまり一般的には使えないシンプルなツールを作ろうとする人はいても良いと思います。 そのような人ですらほとんど存在しないのが現在の Ruby コミュニティの状況です。なぜなのでしょう?
それは、作り始めようとした人に対する大きな障壁が 2 つ存在するからです。
障壁の 1 つ目は、数値配列やグラフィックス機能など、基礎となる機能を提供するライブラリの定番が存在しないことです。 そのため、何かを作り始める前に、現在どのようなライブラリが存在して、それぞれがどんな機能を提供していて、それらの実装はどのくらい信用できるのかを調査しなければならないのです。 面倒臭くてやってられませんね。
障壁の 2 つ目は、仕事で機械学習や統計分析をやっている人の多くが仕事で Python や R を使っていて、Ruby のために自分で作ったものを仕事で使える機会がほとんど無いことです。 プライベートで機械学習や統計分析をやる機会があるとしても、仕事で使い慣れている環境を使う方が良いと考える人は多いでしょう。
このように Ruby で機械学習や統計分析ができない理由は、互いに大きく関係し、強い負のサイクルを形成していることが分かります。
この負のサイクルから抜け出すには、できるだけ早く Ruby で機械学習と統計分析ができる状況を作り、これらの仕事を Ruby でやる人を集める必要があります。
Ruby で機械学習と統計分析ができる状況を作るには 2 つの道があります。1 つ目は「Ruby 独自の生態系を作る」道です。もう 1 つは「Python や R の道具をそのまま利用する」道です。
私は、Ruby のためのデータ分析環境に対して多くの人が求める条件を次の 3 つであると考えています。
私は、これらの条件を全て満足できるのは「Python や R の道具をそのまま利用する」道だと判断しました。 そして、PyCall をはじめとする言語間ブリッジを開発し始めました。
PyCall は Ruby と Python との間のブリッジです。これは、Python のオブジェクトを Ruby から触ること、逆に Ruby のオブジェクトを Python 側に見せることが可能になります。 (本記事の執筆時点では、Ruby オブジェクトを Python 側に見せる機能は未実装です)。これらの機能によって次のことが可能になります。
そのため、私が pycall を開発している目的はデータサイエンスですが、実際に pycall を利用可能な領域はデータサイエンスに限定されません。
PyCall はまだ開発が始まったばかりです。実験的な実装になっていて、GC やスレッドなど気をつけて実装しなければならない部分がまだ手付かずの状態であり、 筆者も開発中に Segmentation Fault を発生させることがよくあります。そのため、実運用での使用はオススメしません。 しかしながら PyCall を使って Ruby で簡単な機械学習やデータの可視化を試すことは既に可能です。
PyCall の利用例は PyCall のリポジトリ内にある examples ディレクトリにまとめています。現在のところ、numpy、matplotlib、pandas、scikit-learn などを pycall を使って利用する例を置いています。
pycall を利用して matplotlib を扱いやすくするためのラッパーとして、同名の matplotlib.gem というライブラリも開発しています (リポジトリ名は matplotlib.rb です)。 このライブラリでは IRuby とのインテグレーションも提供しています。IRuby 上での使い方は以下の iPython notebook をご覧ください。
(本節はほかのブログ記事で筆者が紹介した手順を簡略化して引用したものです)
PyCall は Docker を利用して簡単に試すことができます。Docker が使える環境で下記のコマンドを実行すると、iruby と名付けられたコンテナが起動します。
そして次のようなメッセージが表示されるはずです。
このメッセージ内の URL からトークンの部分をコピペして http://localhost:8888/?token=2f8dda92daa9c28326baf5024d5b8883ca36dcb0e470f885 のような URL を作りブラウザで開いてもらえれば、コンテナ内で動いている jupyter notebook にアクセスできます。
本記事では、Ruby でデータサイエンスの仕事ができない現状について述べ、その状況を解決するために開発している PyCall とその周辺ライブラリについて紹介しました。 PyCall の他にも、R や Julia のようにデータサイエンスに強い言語とのブリッジも開発しています。 この分野に興味がある方は、今後の開発の動向に期待していてください。