具体例で学ぶ!情報可視化のテクニック

第6回 はてなブックマークの可視化(後編)

この記事を読むのに必要な時間:およそ 5 分

はじめに

最終回となる今回は,これまでの学習内容のまとめとして,はてなブックマークの人気エントリーをツリーマップとして可視化します。

この可視化では,ノードの表示位置によってブックマークのカテゴリ特性を,ノードの大きさによってブックマーク数を,そして色によってブックマークの「コメント率」を,それぞれ視覚的に表現します。

ソースコードのダウンロード

今回作成するプログラムのソースコードは,こちらから一括してダウンロードすることができます。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)。

図1

図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()メソッドでベクトルを正規化していることに注意してください。階層的クラスタリングにおけるベクトル間の距離計算時に、特徴の差となる「角度差」を最大限に検出するため,あらかじめベクトルを正規化して長さを揃えているのです。

著者プロフィール

浜本階生(はまもとかいせい)

1981年生まれ。栃木県出身。東京工業大学情報工学科卒業。技術やアイデアの組み合わせから面白いソフトウェアを生み出したいと日々考えている。現在,ブログの解析および視覚化の試みとして「TopHatenar」「Blogopolis」を開発,運用中。

URLhttp://d.hatena.ne.jp/kaiseh/

コメント

コメントの記入