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 %