Wekaの簡単な使い方

オープンソースのデータマイングライブラリWekaを使って予測というか分類というかまあClassifierを作ろうという話。


準備

  1. Wekaを入れる
  2. 学習データを用意する

実装

  1. 分類機を作る
  2. 学習データを作る
  3. (必要なら)評価機を作って性能を確かめる
  4. 分類したい事例を作る
  5. 分類する


学習データは付属のサンプルを使う

@relation weather

@attribute outlook {sunny, overcast, rainy}
@attribute temperature real
@attribute humidity real
@attribute windy {TRUE, FALSE}
@attribute play {yes, no}

@data
sunny,85,85,FALSE,no
sunny,80,90,TRUE,no
overcast,83,86,FALSE,yes
...

天気のデータを表し、それぞれ景色、気温、湿度、風、遊ぶかどうかという属性を持ち、@data以降に学習用のデータを並べていく。


実装。まずは学習データと分類機を生成する。

      DataSource source = new DataSource("weather.arff");
      Instances instances = source.getDataSet();
      instances.setClassIndex(4);
      Classifier classifier = new SMO();
      classifier.buildClassifier(instances);

setClassIndexは分類したい属性の番号。この場合遊ぶか遊ばないかを決めるので4を指定する。Classifierは分類機のインターフェースで、色んな実装があるのでパラメータ等も含め適宜調整する。buildClassifierを呼び出して分類機を構築する。学習に時間がかかるモデルはここで時間を食うので注意。


次に評価。

      Evaluation eval = new Evaluation(instances);
      eval.evaluateModel(classifier, instances);
      System.out.println(eval.toSummaryString());

Evalutionオブジェクトを生成してモデルと学習データを入れる。toSummaryStringでモデルに沿った結果が見れる。この場合

Correctly Classified Instances          12               85.7143 %
Incorrectly Classified Instances         2               14.2857 %
Kappa statistic                          0.6889
Mean absolute error                      0.1429
Root mean squared error                  0.378 
Relative absolute error                 30.7692 %
Root relative squared error             78.8263 %
Total Number of Instances               14

こんな感じ。上二つが成功した数と失敗した数なので、そこそこ分類できてる。ただ、これはデフォルトのテストでそこまで精度が良くないので、ちゃんとしたい場合は適宜いじる。


次に事例データを作る。まずは属性。

      FastVector out = new FastVector(3);
      out.addElement("sunny");
      out.addElement("overcast");
      out.addElement("rainy");
      Attribute outlook = new Attribute("outlook", out, 0);
      Attribute temperature = new Attribute("temperature", 1);
      Attribute humidity = new Attribute("humidity", 2);
      FastVector win = new FastVector(2);
      win.addElement("TRUE");
      win.addElement("FALSE");
      Attribute windy = new Attribute("windy", win, 3);

属性が離散的な値の場合はまずFastVectorを作ってそれぞれの名前を定義してから属性オブジェクトを作る。連続的な値はそのままいける。属性オブジェクトのコンストラクタの最後の引数は属性番号を表すので順に入れていく。


次いでデータ。

      Instance instance = new Instance(5);
      instance.setValue(outlook, "sunny");
      instance.setValue(temperature, 100);
      instance.setValue(humidity, 100);
      instance.setValue(windy, "TRUE");
      instance.setDataset(instances);

Instanceコンストラクタの引数は属性数。それぞれの属性とその値を入れ、データセットを指定する。ここでは超絶蒸し暑くて風がビュンビュン吹いてる日を想定する。


最後に分類結果を出力する。

      double result = classifier.classifyInstance(instance)
      System.out.println(result);

classifyInstanceは連続値にも対応できるようにdoubleで返ってくるが離散値の場合インデックスを表す。この場合0.0がyesで1.0がnoになる。ちなみに結果は

1.0

というわけで、暑い日は家でおとなしくしてましょう。

import weka.classifiers.Classifier;
import weka.classifiers.Evaluation;
import weka.classifiers.functions.SMO;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.converters.ConverterUtils.DataSource;

public class CopyOfWekaTest {

  public static void main(String[] args) {
    try {
      DataSource source = new DataSource("weather.arff");
      Instances instances = source.getDataSet();
      instances.setClassIndex(4);
      Classifier classifier = new SMO();
      classifier.buildClassifier(instances);

      Evaluation eval = new Evaluation(instances);
      eval.evaluateModel(classifier, instances);
      System.out.println(eval.toSummaryString());

      FastVector out = new FastVector(3);
      out.addElement("sunny");
      out.addElement("overcast");
      out.addElement("rainy");
      Attribute outlook = new Attribute("outlook", out, 0);
      Attribute temperature = new Attribute("temperature", 1);
      Attribute humidity = new Attribute("humidity", 2);
      FastVector win = new FastVector(2);
      win.addElement("TRUE");
      win.addElement("FALSE");
      Attribute windy = new Attribute("windy", win, 3);

      Instance instance = new Instance(5);
      instance.setValue(outlook, "sunny");
      instance.setValue(temperature, 100);
      instance.setValue(humidity, 100);
      instance.setValue(windy, "FALSE");
      instance.setDataset(instances);

      double result = classifier.classifyInstance(instance);
      System.out.println(result);
    } catch (Exception e) {
      e.printStackTrace();
    }

  }

}


参考

集合知イン・アクション

集合知イン・アクション

フリーソフトでつくる音声認識システム パターン認識・機械学習の初歩から対話システムまで

フリーソフトでつくる音声認識システム パターン認識・機械学習の初歩から対話システムまで