始めに
機械学習に興味が湧いてきたので、自分でも機械学習のプログラミングをやってみることにした。
機械学習といえば使う言語はpythonがメジャーなのだが、以下の理由で断念した。
Rubyほどじゃないが、Windows環境構築の手順が全く洗練されていない。
(だったら、Linuxの仮想環境を作ればいいのでは?というのはなしで。たかだか、pythonをやるのにLinuxの仮想環境を入れるのはバカバカしすぎる)
ネットで環境構築について調べてみるとpipでインスト―スするやり方annacondaを使ってやるやり方の2種類があって、お互いに互換性がないからどれを使っていいかわからん
機械学習で使うライブラリがpython2系、python3系のどれに対応しているのか全く分からないし、俯瞰的に説明しているサイトがないからものすごく困る。
python2系、python3系を共存させるためには仮想環境を作る必要があるが、どこにどんな仮想環境を作ったか一々自分で覚えるのは面倒くさいし、あほらしい。
この方式をとるのなら、JavaにおけるEcllipseみたいなIDEが必要と思っている
まぁ、要するにpython自体に問題があるのではなく、pythonを取り巻く環境に問題がありすぎるのでお手軽に環境構築ができるJavaで機械学習の勉強をすることにした。
機械学習の勉強が進んで、pythonの実行環境の面倒くささより機械学習の熱意が上回った時点で、改めてpythonで機械学習に取り組もうと思う。
後、断っておくが、python自体はとてもよくできた言語で、プログラミングの記述のし易さはJavaをはっきり上回ると思っている
環境構築手順
- Java Machine Learning(Java-ML)を使ってみよう
http://web.sfc.wide.ad.jp/~tinaba/tutorials/jml-rf/index.html
を参考にした。
上記サイトで紹介されているjarをEcllipseの適当なフォルダに入れてに入れてビルドパスを通すだけ。
Ecllipseの操作に慣れていれば、ものの数分で終わる簡単な作業だ。
Ecllipseの操作に慣れていなくとも、pythonのconndaやらpipを使ってライブラリを導入する手順に比べればはるかに楽だ。
実装ソース
ソースについての説明
Java Machine Learning(Java-ML)を使ってみようで紹介されたソースをベースに、ランダムフォレストを実装してみた。
Java Machine Learning(Java-ML)を使ってみようではループを使って正当判定をしていたが、個人的に繰り返し処理と正当判定のロジックは分離させたかったため、ループをreduceを使った処理に置き換えた
reduceを使ったループ処理はjava8StreamAPI :: reduceによるListの操作を参照のこと
ソース
package mnlearning;import java.io.File;import java.util.HashMap;import java.util.Map;import net.sf.javaml.classification.Classifier;import net.sf.javaml.classification.tree.RandomForest;import net.sf.javaml.core.Dataset;import net.sf.javaml.core.Instance;import net.sf.javaml.tools.data.FileHandler;public class Learning {public static void main(String args[])throws Exception{Dataset data = FileHandler.loadDataset(new File("iris.data"), 4, ",");// ランダムフォレストの作成と学習Classifier rf = new RandomForest(5);rf.buildClassifier(data);// 検証用データの読み込み(同じデータを使用)FileHandler.loadDataset(new File("iris.data"), 4, ",").stream()//reduceでfor文と同じ処理を行う.reduce(new HashMap<String,Integer>(), //ループの初期値を設定する(accum, ins) -> {return createOperation(accum, ins,rf);},//ループで適用する処理を記載する(s,v)->v)//paralle処理を考慮しない場合は適当なラムダ式を渡す//forEachでMapのキーと値の組み合わせを列挙する.forEach((m1,m2)->System.out.println(String.format("%s : %d", m1,m2)));}//検証結果と検証用のデータの検査を行う//Map<String,Integer> accum : 検証結果が格納されている//Instance ins : 検証用データが格納されている//Classifier rf : 学習した結果が格納されているpublic static HashMap<String,Integer> createOperation(Map<String,Integer> accum,Instance ins,Classifier rf){HashMap<String,Integer> m = new HashMap<String,Integer>(accum);//学習した結果が正しければ、正当の件数をカウントアップするif(rf.classify(ins).equals(ins.classValue())){m.compute("correct",(key,value)-> value==null ? 0:value+1);m.compute("wrong",(key,value)-> value==null ? 0:value);//学習した結果が間違っていれば、誤答の件数をカウントアップする}else{m.compute("correct",(key,value)-> value==null ? 0:value);m.compute("wrong",(key,value)-> value==null ? 0:value+1);}return m;}}