配列データをWekaのinstanceに変換する方法
以前,2010-08-31 - 仕事関連のメモにて Weka を用いた k-means 法の実装を述べた.しかし,次元が大きくなると ARFF ファイルを準備するのが大変だし,そもそも既存のプログラムにより生成されたデータを(わざわざ)ファイルを介して Weka に渡すのもおかしな話だということで,Java の基本機能により読み込んだデータからインスタンス集合を生成するプログラムを書いた.
// 配列データを Weka のインスタンスとして k-means 法を適用する.
/*
iris.txt の形式は以下のとおり(属性名を削ったデータ):
----------------------------
5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
....................
----------------------------
*/
// [コンパイル&実行]
// javac -cp weka.jar WekaKmeans.java
// java -cp weka.jar:. WekaKmeans
import java.io.*;
import weka.core.*;
import weka.clusterers.*;
public class WekaKmeans {
public static void main(String[] args) throws Exception {
//属性名の設定
FastVector attributes = new FastVector();
attributes.addElement(new Attribute("sepallength"));
attributes.addElement(new Attribute("sepalwidth"));
attributes.addElement(new Attribute("petallength"));
attributes.addElement(new Attribute("petalwidth"));
//インスタンス集合の定義
Instances dataClusterer = new Instances("iris", attributes, 0);
/// iris.txt からのデータ読み込み & インスタンス集合の生成(ここから) ///
try {
BufferedReader fin = new BufferedReader(
new FileReader("iris.txt"));
String s;
while((s = fin.readLine()) != null){
String[] ss = s.split(",");
//インスタンス1個分のデータを配列に入れておいて・・・
double[] data = new double[4];
for(int i = 0; i < 4; i++) data[i] = Double.parseDouble(ss[i]);
//インスタンスを作り・・・
Instance instance = new Instance(1.0, data);
//インスタンス集合に追加(登録)する
dataClusterer.add(instance);
}
fin.close();
} catch(Exception e){
System.err.println("データ読み込み中にエラー");
System.exit(1);
}
/// iris.txt からのデータ読み込み & インスタンス集合の生成(ここまで) ///
////////// clusterer(クラスタリングモデル)を作る //////////
// クラスタリング手法として k-means 法を用いる
SimpleKMeans clusterer = new SimpleKMeans();
clusterer.setNumClusters(3); // クラスタ数の設定
clusterer.buildClusterer(dataClusterer); //学習データを与えて clusterer を構築
////////// clusterer(クラスタリングモデル)の評価 //////////
ClusterEvaluation eval = new ClusterEvaluation();
eval.setClusterer(clusterer); // 評価したい clusterer を設定
eval.evaluateClusterer(dataClusterer); // テストデータとして元データを与える
////////// clusterer の評価結果(サマリ)を出力 //////////
System.out.println(eval.clusterResultsToString());
// クラスタリングの結果として割り当てられたクラス番号を得る
double[] assignment = eval.getClusterAssignments();
for(int i = 0; i < assignment.length; i++){
System.out.print((int)assignment[i] + " ");
}
}
}実行結果は以下のとおり.ARFFファイルからデータを読み込んだ場合と同じ結果である(当然か).
kMeans
======
Number of iterations: 6
Within cluster sum of squared errors: 6.998114004826762
Missing values globally replaced with mean/mode
Cluster centroids:
Cluster#
Attribute Full Data 0 1 2
(150) (61) (50) (39)
=========================================================
sepallength 5.8433 5.8885 5.006 6.8462
sepalwidth 3.054 2.7377 3.418 3.0821
petallength 3.7587 4.3967 1.464 5.7026
petalwidth 1.1987 1.418 0.244 2.0795
Clustered Instances
0 61 ( 41%)
1 50 ( 33%)
2 39 ( 26%)
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 2 2 2 2 0 2 2 2 2 2 2 0 2 2 2 2 2 0 2 0 2 0 2 2 0 0 2 2 2 2 2 0 0 2 2 2 0 2 2 2 0 2 2 2 0 2 2 0