『学んだ数式をコーディングする環境』をJuliaで構築

機械学習データマイニングのバックグラウンドにある数式をきちんと学んだら、実際にアルゴリズムをコードとして書いてみるととても力が着くと思います。便利なパッケージやツールも色々とありますが、ソフトウェアエンジニアだったら製品開発のために独自に実装できるようになりたいって思うものですよね?

プロダクション利用を見越して、かつ、学べるソフトウェア環境として候補は以下かなと思います。

全部試してみたいのですがとりあえず面白そうなJuliaで環境構築してみます。(すみません、私はWindows+UbuntuなユーザなのでMacや他のLinuxについてはもし参考になれば幸いです)

IDE(統合開発環境)

JuliaはShell+Emacsでも便利だと思いますがWindows/Mac/Linuxで使えるJuliaStudioというのが便利です。Windowsなら普通にインストーラをダウンロードして実行すればOK.

JuliaStudioはJulia処理系を同梱していて、インストールディレクトリ(C:\Program Files\JuliaStudio-0.x.x\julia-studio)に一緒に入ります。

Julia処理系を単体でインストールしてJuliaStudioから指定することも出来ます。(「Tool」→「Options」→「Julia」で処理系のパスを指定)

可視化ライブラリ

Juliaのホームページに代表的な可視化ライブラリがリストアップされてます

  • Winston

(Tclの)TkベースのGUIでプロットするもので、Windowsで試してみましたがレンダリングがちょっと遅いし、リサイズしないとリドローのイベントが伝わらなかったりイマイチでした。

  • Gadfly(個人的にオススメ)

プロットしたグラフを画像ファイルや、最近流行りのD3.js用のjsコードを吐くことも出来て、試してみましたがなかなか良いです。

  • Gaston

Gnuplotベースのプロットライブラリだそうです。試してないのでちょっとわかりません。

Pythonのmatplotlibを利用するライブラリだそうです。これも試してませんが、Pythonを良く使ってる人はいいんじゃないでしょうか。あと上のGadflyと比べてレンダリングスピードが速そうな雰囲気です。

とりあえずGadfly+D3.jsをメインに使うことにします。

Gadfly+D3.js

Juliaでパッケージをインストールするには処理系のプロンプトで

julia> Pkg.add("Gadfly")
(色々メッセージが出てくる)
julia> Pkg.build()
(色々メッセージが出てくる)

として、Julia処理系を再起動します。JuliaStudioならメニューからReset Console(F3)でOK。(再起動しないと色々ハマるので注意)

D3.jsはjQueryのようにHTMLのマークアップに装飾やグラフィックを乗せていくというノリのグラフィックライブラリです。Webとの親和性は抜群だと思います。

Gadflyはグラフの画像を出力する代わりに「D3.jsを使ってグラフを描くコード」を出力してくれます。以下のような感じ。

julia> using Gadfly
julia> draw(D3("draw.js", 6inch, 6inch), plot(x=collect(1:100), y=sort(rand(100)), Geom.line))

これを表示するHTMLページを以下のように作ります。

<!DOCTYPE html>
   <html lang="en">
      <head>
         <meta charset="utf-8">
         <title>D3 Test</title>
         <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
         <script type="text/javascript" src="js/gadfly.js"></script>
      </head>
      <body>
         <div id="graph"></div>
         <script type="text/javascript" src="./draw.js"></script>
         <script type="text/javascript">draw("#graph")</script>
      </body>
</html>

グラフを表示したい箇所に空のdivタグを置いて、そこのセレクタ名指定してdraw()関数(Gadflyが自動出力したjsコードに定義される関数)を呼ぶだけです。これでHTMLファイルをブラウザで開けば以下のようにグラフが表示されます。

Julia側でプロットしなおしたらブラウザをリロードすればグラフを再描画出来るので、使用感は普通にグラフィックパッケージを使っているのと大体同じになるところが素晴らしい。あと、JuliaStudioはHTMLファイルを読み込んで表示できるので、RStudioみたいな感じでIDEの中にグラフを表示させることも出来ます。*1

最小二乗法をやってみる

有志で大体隔週でやっているベイズ勉強会でやったことを試してみたいというのが本取組みの動機なので、とりあえず最小二乗法をやってみます。

sin関数なy=a*sin(x)+e(正規誤差)のxが0から2πまでをサンプル点約10個という設定でやります。基底関数がsin(x)として疑似逆行列を求めてaの推定結果をプロット。a=2, 正規誤差は平均ゼロで標準偏差が0.5という設定でやってみます。ちゃんと推定できるかな?

using Distributions
using DataFrames
using Gadfly

function my_inv(x)
  return (ndims(x)==1 ? 1/x : inv(x))
end

base=collect(0:0.3:2*pi)
N=length(base)
x=sin(base)

a=2
e=rand(Normal(0,0.5),N)
y=sin(base)*a+e

a1=my_inv(x'*x)*x'*y

y1=sin(base)*a1[1]

df=DataFrame(x=vcat(base,base),y=vcat(y,y1),col=vcat(ones(Int,N),zeros(Int,N)))

println(a1)
draw(D3("draw.js",6inch,3inch),plot(df,x="x",y="y",color="col",Geom.line))

以下、実行結果。

標準出力(aの推定値)

1.7169439098878851

まぁ大体2ですね。何回か試しましたが2の周辺をウロウロします。推定値は最良不偏推定量になるので、試行ごとの推定値をヒストグラム化すれば正規分布っぽくなるはずです。(あとで暇なときやる)
行列計算等は内部でBLASLAPACKを使ってるそうなので凄く速いのでしょうね。行列やベクトルの式の書き方もストレートで良いです。で、グラフが以下。

色使いとかもろもろ、ものすごーく見づらい感じでイマイチですね。。そうにしてもD3.jsコードを吐くというアイディアは凄くよいと思うのでなんなら僕が機能をどんどんpull requestする感じでリッチにしていきたいところです。

Julia使用感

JuliaはR言語と比べると若干データの基本的な処理周りで融通が利かない面があったりしますが、まずはチートシートを見たりしながらコード書いて慣れるしかないですね。

あと、LLVMを使ってて実行速度が速いのはいいのですが初回の読み込みが遅いので、プリコンパイルの仕組みがもうちょっと使いやすくなるといいと思います。LLVMにはそういう機能があるしJuliaも少しサポートしてるのであとは処理系の使い勝手の良さの部分で改良が進めば、という感じでしょうか。それと型推論を行ったうえでオーバーロードしたりするみたいで便利なのですが、そこがちゃんと機能するのかもよくわからなくて不安です。使い慣れてくれば色々分かってくるのかな。

というわけで

Juliaを試してみました。実行速度はかなり早くて分散並列処理もサポートしてたりと発展性は期待できますが、現状はどうもやはりplot関係のツール周りがpythonやRと比べると見劣りします。

なので似たようなことをPandas+Scipyでやってみて使用感を比べながら今後の道具立てをそろえていこうかなって思います。

*1:と、便利なGadflyですが手元の環境ではドキュメント通りやると点のプロットが失敗する場合があって、上記コードはラインでつないだグラフ(Geom.line)をとりあえず使ってます。(1時間程ソース読んだが原因究明できず。あとでちゃんと調べてpull requestなりなんなりします。