3章 その9 階層的クラスタを作成
単語出現回数のリストを要素(vec)に持つ2分木ノードbiclusterをつなぎあわせて、p.36で解説されている内容が近いblog同士の階層的クラスタを作る。
距離の計算は関数ポインタになっていたので、Object#method関数を使って http://www.ruby-lang.org/ja/man/html/Method.html self.method(distance).call()した。
p.39より、cluster.rbにhcluster関数を追加
http://www.bitbucket.org/shokai/collective-intelligence-study/src/82884830d372/03/clusters.rb
# 階層的クラスタを作る def hcluster(rows, distance=:pearson) distances = Hash.new currentclustid = -1 # クラスタは最初は行たち clust = Array.new for i in 0...rows.length c = Bicluster.new(rows[i]) c.id = i clust.push(c) end while clust.length > 1 lowestpair = [0,1] closest = self.method(distance).call(clust[0].vec, clust[1].vec) # すべての組をループし、もっとも距離の近い組を探す for i in 0...clust.length for j in i+1...clust.length # 距離をキャッシュしてない時、新しく計算する if !distances.key?([clust[i].id, clust[j].id]) # hashのkeyとして配列を使う distances[[clust[i].id, clust[j].id]] = self.method(distance).call(clust[i].vec, clust[j].vec) end d = distances[[clust[i].id, clust[j].id]] if d < closest closest = d lowestpair = [i,j] end end end # 2つのクラスタの平均を計算する mergevec = Array.new for i in 0...clust[0].vec.length m = (clust[lowestpair[0]].vec[i] + clust[lowestpair[1]].vec[i])/2.0 mergevec.push(m) end # 新たなクラスタを作る newcluster = Bicluster.new(mergevec, clust[lowestpair[0]], clust[lowestpair[1]], closest, currentclustid) # 元のセットではないクラスタのIDは負にする currentclustid -= 1 clust.delete_at(lowestpair[1]) clust.delete_at(lowestpair[0]) clust.push(newcluster) end return clust[0] end
動くか試す
#!/opt/local/bin/ruby require 'rubygems' require 'pp' require 'clusters.rb' cs = Clusters.new blognames,words,data = cs.readline('myblogdata.txt') clust = cs.hcluster(data) pp clust
clustの中身は5万行ぐらいある
#<Bicluster:0x16a8d98 @distance=1.01344976546645, @id=-96, @left= #<Bicluster:0x118f5dc @distance=0.942133193351032, @id=-92, @left= #<Bicluster:0x6ecf80 @distance=0.0, @id=17, @left=nil, @right=nil, @vec= [0, 0, 0, 1, 0, 2, 0, 0, 1, 1, 10, 0, 0, 0,
長いので略