はじめに
最終回となる今回は,これまでの学習内容のまとめとして,はてなブックマークの人気エントリーをツリーマップとして可視化します。
この可視化では,ノードの表示位置によってブックマークのカテゴリ特性を,ノードの大きさによってブックマーク数を,そして色によってブックマークの「コメント率」を,それぞれ視覚的に表現します。
ソースコードのダウンロード
今回作成するプログラムのソースコードは,こちらから一括してダウンロードすることができます。ZIPファイルを展開して生成されるフォルダを,プロジェクトとしてNetBeansに読み込むことも可能です。
特徴量ベクトルの生成
前回のプログラムでは,はてなブックマークにユーザーが付与したタグの一覧を収集しました。このタグ情報を特徴量ベクトルに変換し,第2回で作成したMultiVectorクラスのインスタンスとして表現することを考えます。
このとき問題となるのは,MultiVectorクラスのベクトル要素の添え字が整数である一方,タグが文字列であるため,タグをそのまま添え字としては使用できないことです。
そこで,タグを整数インデックスに変換するIndexMapperクラスを以下のように作成します。IndexMapperクラスは,put()メソッドで新しいタグが追加されるたびに,0, 1, 2, ...と順にインデックスを割り振り,ハッシュマップに記憶します。割り振られたインデックスは,後からget()メソッドで取得することができます。
リスト1 IndexMapper.java
public class IndexMapper {
private Map<Object, Integer> map = new HashMap<Object, Integer>();
public int size() { return map.size(); }
public boolean contains(Object obj) {
// インデックスが割り振り済みであるかどうかを調べる
return map.containsKey(obj);
}
public void put(Object obj) {
if (!contains(obj)) {
// 新しいオブジェクトの場合,現在のサイズを新規インデックスとして割り振る
int newIndex = size();
map.put(obj, newIndex);
}
}
public int get(Object obj) {
// インデックスが割り振られていない場合は例外を発生
if (!contains(obj)) {
throw new IllegalArgumentException("Object is not found.");
}
// インデックスを返す
return map.get(obj);
}
}
IndexMapperクラスを使って,ブックマークエントリーに付与された全てのタグをインデックス化し,タグの出現回数を成分とすることで,エントリーの特徴量を持つベクトルを生成することができます(図1)。
ブックマークノードクラスの作成
タグのベクトル化が可能となったところで,ブックマークエントリーのノードクラスとなるBookmarkItemクラスを作成します。このクラスは,第2回で作成したItemクラスを継承しており,階層的クラスタリングの入力ノードとして使用することができます。
リスト2 BookmarkItem.java(部分)
public class BookmarkItem extends Item {
...
public BookmarkItem(Bookmark bookmark, BookmarkDetail detail,
IndexMapper mapper) {
// ブックマーク数をそのまま面積化すると比率が極端になるので
// 平方根をとって調整する
super(bookmark.title, tagsToVector(detail, mapper),
Math.sqrt(detail.bookmarkCount));
this.bookmark = bookmark;
this.detail = detail;
}
private static MultiVector tagsToVector(BookmarkDetail detail,
IndexMapper mapper) {
MultiVector vector = new MultiVector(mapper.size());
for (String tag : detail.tags) {
if (mapper.contains(tag)) {
int index = mapper.get(tag);
vector.set(index, vector.get(index) + 1);
}
}
vector.normalize(); // ベクトルを正規化する
return vector;
}
}
MultiVectorオブジェクトを作成した後,normalize()メソッドでベクトルを正規化していることに注意してください。階層的クラスタリングにおけるベクトル間の距離計算時に、特徴の差となる「角度差」を最大限に検出するため,あらかじめベクトルを正規化して長さを揃えているのです。

