Coursera Machine LearningをJuliaでやる



課題提出に使ったJulia用のスクリプトは、[こちらのリポジトリ](https://github.com/homuler/coursera-ml-julia)においています。
Juliaで課題を提出したい方は、是非ご利用ください。多少手間が省けるかと。

# Coursera Machine Learningについて
Andrew Ng氏による、機械学習のオンライン講座です。
https://www.coursera.org/learn/machine-learning

以下の記事などで紹介されています。
http://qiita.com/daxanya1/items/218f2e3b922142550ef9

講座を進めていくと、途中で課題（Assignment）を提出する必要があるのですが、これらはプログラムを書いて、その出力をサーバに送信する形式になっています。
公式ではMatlabかOctaveで解くことになっていますが、今回はこれをJuliaで解いてみたお話です。

# Why Julia?
Octaveが遅すぎるなどして、この先使っていく気が全くせず = Octaveを全く覚える気になれず。
[Julia](http://julialang.org/)は書いたことがなかっものの、気にはなっていたのと、比較的速いということも聞いていたので、この機会に試してみようということでやってみました。
実際にやってみた感想として、OctaveやMatlabとsyntaxや関数が近いことが多いので、比較的課題に取り組みやすい印象はあります。

Python用のスクリプトを公開している人もいて（[解答コードが書かれていないものもある](https://github.com/mstampfer/Coursera-Stanford-ML-Python)）、これらを使ってPythonで解いても良かったのですが、「PythonよりもOctaveのほうがいいよー」という趣旨の説明が講義の中でもされていた気がするので（学習コストに関する文脈）、Pythonは回避しました。

# JuliaでAssignmentをやる
提供されているOctaveのスクリプトを、Juliaで書き直してあげればよいわけですが、問題を解くだけであれば、さほど大変ではないです。

例えばですが、OctaveのExercise1用のスクリプトのある部分はこうなっていて、

```octave:ex1.m

%% ======================= Part 2: Plotting =======================
printf('Plotting Data ...\n')
data = load('ex1data1.txt');
X = data(:, 1); y = data(:, 2);
m = length(y); % number of training examples

% Plot Data
% Note: You have to complete the code in plotData.m
plotData(X, y);

fprintf('Program paused. Press enter to continue.\n');
pause;
```

Juliaで書き換えるとこんな感じになります。

```julia:ex1.jl
using Gadfly

@printf("Plotting Data ...\n")
data = readcsv("ex1data1.txt")
X = data[:, 1]
y = data[:, 2]
m = length(y) # number of training examples

# Plot Data
# Note: You have to complete the code in plotData.jl

l1 = plotData(X, y)
draw(SVGJS("ex1-dataset.js.svg", 6inch, 6inch), plot(l1))

println("Program paused. Press enter to continue.")
readline()
```

他のスクリプトでも、大体変更が入るのはこの例と同じで、

1. ファイル入力、標準出力
    - `fprintf` -> `@printf`や`println`に
    - ファイル入力は適当に
    - .matを読むときは、PyCall使って、scipy.ioの`loadmat`メソッドを呼び出す

1. 配列、行列の操作
    - `X(1, :)` -> `X[1, :]`
    - `[X, Y]` -> `[X; Y]` or `[X Y]` ... などなど

1. Data Visualization
    - 適当なライブラリを使う
       - PyPlotなら、matplotlibを使えて、使い方もOctaveの関数とかなり近くなる
       - Gadfly, Plotlyなども使えるが、結構書き直しが必要
    - meshgridに相当する関数はないので、自力で書く

といったところで、他はそのままで動くことが多いです。
plotDataあたりが気持ち悪いことになっていますが、そのあたりは後述します。

## Data Visualization
やらなくても、課題を提出する上では問題ないです。
きれいに出力したい気持ちはありつつ、結構ハマったりします。

### PyPlot  

多分一番楽です。
以下単純にデータセットをplotするだけのコードですが、コードを比較的近い対応で書き直すことができます。  
![coursera-lr-pyplot.png](https://qiita-image-store.s3.amazonaws.com/0/75199/7f2812f4-1ff1-c9bb-ab5e-0b4b6b2ff5e3.png)

以下、上図のplotを行うコードです。
都合により、直線を引く部分は書いていないですが、

```octave:ex5.m
figure;
hold on;

plot(x=X[ps, 1], y=X[ps, 2], color="b");
plot(x=X[ns, 1], y=X[ns, 2], color="y");
xlabel("Exam 1 score");
ylabel("Exam 2 score");

hold off;
```

PyPlotを使ってJuliaで書くと、

```jl:ex5.jl
using PyPlot

figure()
hold(true)

scatter(x=X[ps, 1], y=X[ps, 2], color="b")
scatter(x=X[ns, 1], y=X[ns, 2], color="y")
xlabel("Exam 1 score")
ylabel("Exam 2 score")

hold(false)
```

ただ、NumpyのオブジェクトをJuliaのデータに変換する操作などがバックで走るときに、たまにキレイに動いてくれないときがあって、PyCallに依存すると後々気持ち悪そうな気がしています。

### Gadfly  
先ほどの図をGadflyで書くとこんな感じになります（微妙に対応していない部分もありますが）。

![coursera-lr-gadfly.png](https://qiita-image-store.s3.amazonaws.com/0/75199/86cb0c69-e431-232c-a279-2d8d2a68509b.png)

同じく都合により、直線を引くコードがないですが、

```jl:ex5.jl
l1 = layer(x=X[ps, 1], y=X[ps, 2], Geom.point, Theme(default_color=colorant"blue"))
l2 = layer(x=X[ns, 1], y=X[ns, 2], Geom.point, Theme(default_color=colorant"yellow"))
plot(l1, l2 Stat.xticks(ticks=collect(30:10:100)), Stat.yticks(ticks=collect(30:10:100)),
      Guide.xlabel("Exam 1 score"), Guide.ylabel("Exam 2 score"))
```

とりあえず重いです。ひたすら重いです。
図は多少洗練された感じになりますが。
その他にも  
  
1. legendを扱う標準的な方法がない
    - 工夫すれば大体できるとは思われるものの、いずれにせよ面倒
1. layerの取り扱いが微妙。
  - 既存のplotに上書きしようとすると、layerを使う必要がある（ので、plotDataとかでlayerを返したりしてました。。関数の名前を変えれば、多少はましな印象になるかもしれないですが）
  - contour使うと、plotや他のlayerで、特定の属性（Scale系など。点の色を数値によって連続的に変えたい時に萎える）が使えなくなる
1. surfなど、3Dのplot用の関数がないなど、必要な関数が揃っていない  
 
など、微妙な点はいくつかあります。SVGを出力してくれて、ブラウザ上で操作できるのは嬉しいので使ってました。

※Juliaのインタプリタでplot関数を呼び出すと、ブラウザが起動してくれるのですが、plotを呼んでいるファイルを読み込んでも、ブラウザは自動では起動してくれなかったです。やり方が間違っているような気はしますが、まだ詳しくは調べていません。

### Plotly
まだ使ってないので、これから使ってみようと思ってます。
Gadflyよりは速そうなのと、 3Dのplotができるので、PyPlotに頼らなくて良くなると期待。

# 結果
- 時間はかかる
    - 予めOctaveで用意されている部分も含めて、Juliaで書いていくため
    - 500行ぐらいのスクリプトを、Juliaで書き直さなければいけない時もあり、後半は結構辛くなった
    - 変更箇所が多くないとはいえ、エラーが起きたら直すといったスタイルでやっていたせいかも
- ライブラリは強力
    - 線形代数系はよさげ。blas.jlとかあって、熱い（速度は計ってないですが）
    - コードは表現力も高く、書きやすい
- 確かに速い
    - 当たり前ですが、Octaveとは比べ物にならないぐらい速かったです
  
とまれ、Juliaいいね！（これが言いたかった）