配列データを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