Weka を用いたクラスタリング
k-means法により Iris データをクラスタリングした.
import java.io.*; import weka.core.*; import weka.clusterers.*; import weka.filters.*; import weka.filters.unsupervised.attribute.Remove; public class WekaClustering { public static void main(String[] args) throws Exception { ////////// データの読み込み ////////// //データ(事例)を ARFF ファイルから読み込む Instances data = new Instances(new BufferedReader(new FileReader(args[0]))); //読み込んだデータセットにて,クラスを表す属性の番号を指定する //(注) Iris データは最後の属性がクラス名を表すから,この指定でよい. //(注) numAttributes() は属性数を返す. data.setClassIndex(data.numAttributes() - 1); ////////// クラス情報なしのデータセットを作る ////////// // Remove は,データセットから指定された範囲の属性を除去するフィルタ Remove filter = new Remove(); //除去する属性の番号(クラスの属性番号)を指定 filter.setAttributeIndices("" + (data.classIndex() + 1)); //入力される事例のフォーマットをデータセットから読み込む filter.setInputFormat(data); //データセットにフィルタをかませて,クラス列を除いた新データセットを作る Instances dataClusterer = Filter.useFilter(data, filter); //(メモ) 新データセットを出力したら,確かにクラス列が除去されていた /* System.out.println(dataClusterer); */ ////////// clusterer(クラスタリングモデル)を作る ////////// // クラスタリング手法として EM を用いる //EM clusterer = new EM(); // クラスタリング手法として k-means 法を用いる SimpleKMeans clusterer = new SimpleKMeans(); clusterer.setNumClusters(3); // クラスタ数の設定 clusterer.buildClusterer(dataClusterer); ////////// クラスタリングの結果について ////////// //各クラスタのサイズを得る int x[] = clusterer.getClusterSizes(); System.out.println("=== クラスタサイズ ==="); for(int i = 0; i < x.length; i++){ System.out.println("[" + i + "] " + x[i]); } ////////// clusterer の評価 ////////// ClusterEvaluation eval = new ClusterEvaluation(); eval.setClusterer(clusterer); // clusterer の設定 eval.evaluateClusterer(data); // クラスタリング対象として元データを与える ////////// clusterer の評価結果を出力 ////////// System.out.println(eval.clusterResultsToString()); } }
実行結果は以下のとおり:
=== クラスタサイズ === [0] 61 [1] 50 [2] 39 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%) Class attribute: class Classes to Clusters: 0 1 2 <-- assigned to cluster 0 50 0 | Iris-setosa 47 0 3 | Iris-versicolor 14 0 36 | Iris-virginica Cluster 0 <-- Iris-versicolor Cluster 1 <-- Iris-setosa Cluster 2 <-- Iris-virginica Incorrectly clustered instances : 17.0 11.3333 %
eval.evaluateClusterer() に渡す instances を dataClusterer にすると,次のようにサマリが出力される.
=== クラスタサイズ === [0] 61 [1] 50 [2] 39 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%)
ClusterEvaluation.getClusterAssignments() を用いて,クラスタリングされた結果として,いずれのクラスタに割り当てられたかを調べる機能を付加した.
import java.io.*; import weka.core.*; import weka.clusterers.*; import weka.filters.*; import weka.filters.unsupervised.attribute.Remove; public class WekaClustering { public static void main(String[] args) throws Exception { ////////// データの読み込み ////////// //データ(事例)を ARFF ファイルから読み込む Instances data = new Instances(new BufferedReader(new FileReader(args[0]))); //読み込んだデータセットにて,クラスを表す属性の番号を指定する //(注) Iris データは最後の属性がクラス名を表すから,この指定でよい. //(注) numAttributes() は属性数を返す. data.setClassIndex(data.numAttributes() - 1); ////////// クラス情報なしのデータセットを作る ////////// // Remove は,データセットから指定された範囲の属性を除去するフィルタ Remove filter = new Remove(); //除去する属性の番号(クラスの属性番号)を指定 filter.setAttributeIndices("" + (data.classIndex() + 1)); //入力される事例のフォーマットをデータセットから読み込む filter.setInputFormat(data); //データセットにフィルタをかませて,クラス列を除いた新データセットを作る Instances dataClusterer = Filter.useFilter(data, filter); //(メモ) 新データセットを出力したら,確かにクラス列が除去されていた /* System.out.println(dataClusterer); */ ////////// clusterer(クラスタリングモデル)を作る ////////// // クラスタリング手法として EM を用いる //EM clusterer = new EM(); // クラスタリング手法として k-means 法を用いる SimpleKMeans clusterer = new SimpleKMeans(); clusterer.setNumClusters(3); // クラスタ数の設定 clusterer.buildClusterer(dataClusterer); ////////// クラスタリングの結果について ////////// //各クラスタのサイズを得る int x[] = clusterer.getClusterSizes(); System.out.println("=== クラスタサイズ ==="); for(int i = 0; i < x.length; i++){ System.out.println("[" + i + "] " + x[i]); } ////////// clusterer の評価 ////////// ClusterEvaluation eval = new ClusterEvaluation(); eval.setClusterer(clusterer); // clusterer の設定 eval.evaluateClusterer(data); // クラスタリング対象として元データを与える // クラスタリングの結果として割り当てられたクラス番号を得る double assign[] = eval.getClusterAssignments(); for(int i = 0; i < assign.length; i++){ System.out.println(i + ":" + assign[i] + ":" + data.instance(i).stringValue(data.numAttributes() - 1)); } ////////// clusterer の評価結果(サマリ)を出力 ////////// System.out.println(eval.clusterResultsToString()); } }
x-means法
パラメータ設定をしていない(デフォルトの)x-means に Iris データを食わせたら,クラスタ数が2個になった.クラス間に多少の被りがあるとはいえ,う〜む.
// クラスタリング手法として x-means 法を用いる XMeans clusterer = new XMeans(); clusterer.buildClusterer(dataClusterer);
実行結果は以下のとおり:
0:1.0:Iris-setosa 1:1.0:Iris-setosa 2:1.0:Iris-setosa 3:1.0:Iris-setosa 4:1.0:Iris-setosa 5:1.0:Iris-setosa 6:1.0:Iris-setosa 7:1.0:Iris-setosa 8:1.0:Iris-setosa 9:1.0:Iris-setosa 10:1.0:Iris-setosa 11:1.0:Iris-setosa 12:1.0:Iris-setosa 13:1.0:Iris-setosa 14:1.0:Iris-setosa 15:1.0:Iris-setosa 16:1.0:Iris-setosa 17:1.0:Iris-setosa 18:1.0:Iris-setosa 19:1.0:Iris-setosa 20:1.0:Iris-setosa 21:1.0:Iris-setosa 22:1.0:Iris-setosa 23:1.0:Iris-setosa 24:1.0:Iris-setosa 25:1.0:Iris-setosa 26:1.0:Iris-setosa 27:1.0:Iris-setosa 28:1.0:Iris-setosa 29:1.0:Iris-setosa 30:1.0:Iris-setosa 31:1.0:Iris-setosa 32:1.0:Iris-setosa 33:1.0:Iris-setosa 34:1.0:Iris-setosa 35:1.0:Iris-setosa 36:1.0:Iris-setosa 37:1.0:Iris-setosa 38:1.0:Iris-setosa 39:1.0:Iris-setosa 40:1.0:Iris-setosa 41:1.0:Iris-setosa 42:1.0:Iris-setosa 43:1.0:Iris-setosa 44:1.0:Iris-setosa 45:1.0:Iris-setosa 46:1.0:Iris-setosa 47:1.0:Iris-setosa 48:1.0:Iris-setosa 49:1.0:Iris-setosa 50:0.0:Iris-versicolor 51:0.0:Iris-versicolor 52:0.0:Iris-versicolor 53:0.0:Iris-versicolor 54:0.0:Iris-versicolor 55:0.0:Iris-versicolor 56:0.0:Iris-versicolor 57:0.0:Iris-versicolor 58:0.0:Iris-versicolor 59:0.0:Iris-versicolor 60:0.0:Iris-versicolor 61:0.0:Iris-versicolor 62:0.0:Iris-versicolor 63:0.0:Iris-versicolor 64:0.0:Iris-versicolor 65:0.0:Iris-versicolor 66:0.0:Iris-versicolor 67:0.0:Iris-versicolor 68:0.0:Iris-versicolor 69:0.0:Iris-versicolor 70:0.0:Iris-versicolor 71:0.0:Iris-versicolor 72:0.0:Iris-versicolor 73:0.0:Iris-versicolor 74:0.0:Iris-versicolor 75:0.0:Iris-versicolor 76:0.0:Iris-versicolor 77:0.0:Iris-versicolor 78:0.0:Iris-versicolor 79:0.0:Iris-versicolor 80:0.0:Iris-versicolor 81:0.0:Iris-versicolor 82:0.0:Iris-versicolor 83:0.0:Iris-versicolor 84:0.0:Iris-versicolor 85:0.0:Iris-versicolor 86:0.0:Iris-versicolor 87:0.0:Iris-versicolor 88:0.0:Iris-versicolor 89:0.0:Iris-versicolor 90:0.0:Iris-versicolor 91:0.0:Iris-versicolor 92:0.0:Iris-versicolor 93:0.0:Iris-versicolor 94:0.0:Iris-versicolor 95:0.0:Iris-versicolor 96:0.0:Iris-versicolor 97:0.0:Iris-versicolor 98:0.0:Iris-versicolor 99:0.0:Iris-versicolor 100:0.0:Iris-virginica 101:0.0:Iris-virginica 102:0.0:Iris-virginica 103:0.0:Iris-virginica 104:0.0:Iris-virginica 105:0.0:Iris-virginica 106:0.0:Iris-virginica 107:0.0:Iris-virginica 108:0.0:Iris-virginica 109:0.0:Iris-virginica 110:0.0:Iris-virginica 111:0.0:Iris-virginica 112:0.0:Iris-virginica 113:0.0:Iris-virginica 114:0.0:Iris-virginica 115:0.0:Iris-virginica 116:0.0:Iris-virginica 117:0.0:Iris-virginica 118:0.0:Iris-virginica 119:0.0:Iris-virginica 120:0.0:Iris-virginica 121:0.0:Iris-virginica 122:0.0:Iris-virginica 123:0.0:Iris-virginica 124:0.0:Iris-virginica 125:0.0:Iris-virginica 126:0.0:Iris-virginica 127:0.0:Iris-virginica 128:0.0:Iris-virginica 129:0.0:Iris-virginica 130:0.0:Iris-virginica 131:0.0:Iris-virginica 132:0.0:Iris-virginica 133:0.0:Iris-virginica 134:0.0:Iris-virginica 135:0.0:Iris-virginica 136:0.0:Iris-virginica 137:0.0:Iris-virginica 138:0.0:Iris-virginica 139:0.0:Iris-virginica 140:0.0:Iris-virginica 141:0.0:Iris-virginica 142:0.0:Iris-virginica 143:0.0:Iris-virginica 144:0.0:Iris-virginica 145:0.0:Iris-virginica 146:0.0:Iris-virginica 147:0.0:Iris-virginica 148:0.0:Iris-virginica 149:0.0:Iris-virginica XMeans ====== Requested iterations : 1 Iterations performed : 1 Splits prepared : 2 Splits performed : 1 Cutoff factor : 0.5 Percentage of splits accepted by cutoff factor : 100 % ------ Cutoff factor : 0.5 ------ Cluster centers : 2 centers Cluster 0 6.261999999999998 2.872000000000001 4.906000000000001 1.6760000000000006 Cluster 1 5.005999999999999 3.4180000000000006 1.464 0.2439999999999999 Distortion: 37.234831 BIC-Value : 88.948959 Clustered Instances 0 100 ( 67%) 1 50 ( 33%) Class attribute: class Classes to Clusters: 0 1 <-- assigned to cluster 0 50 | Iris-setosa 50 0 | Iris-versicolor 50 0 | Iris-virginica Cluster 0 <-- Iris-versicolor Cluster 1 <-- Iris-setosa Incorrectly clustered instances : 50.0 33.3333 %