"Collective Intelligence"のサンプルを,はてなに対応させてみた
本の方では del.icio.us のブックマークを取得して,自分(じゃなくてもいいんだけど)と似ている人を探し,その人のリンクでまだ自分が登録していないものをお勧めするプログラムが出てくる。それを,はてなに対応させてみた。こっちもやや長いけど hatena_rec.rb。
require 'open-uri' require 'rss' require 'uri' def init_dict(tag, count=5, users=30) result = Hash.new # 指定のキーワードのブックマーク一覧(rss形式 人気順/新着順) # sk = 'hot' # 注目 # sk = 'eid' # 新着順 sk = 'count' # 人気順 rss_uri = "http://b.hatena.ne.jp/t/#{URI.encode(tag)}?mode=rss&sort=#{sk}&threshold=3" 3.times do |i| begin open(rss_uri) do |rss_src| popular_rss = RSS::Parser.parse(rss_src) # そのurlをブックマークしているユーザの一覧(rss形式) popular_rss.items[0,count].each do |item| begin open("http://b.hatena.ne.jp/entry/rss/#{item.link}") do |src| # ブックマークしているユーザ一覧のrssは不正な形式(<items>の中に<rdf:Seq>が無い)なので # parseの第二パラメータにfalseを渡す rss = RSS::Parser.parse(src, false) rss.items[0,users].each do |item| # ここではユーザ毎に空ハッシュのみ用意する result[item.title] = Hash.new end end rescue puts "#{$!} : cannot get user list" end end end break rescue puts "#{$!} : cannot get popular bookmarks" sleep(5) next end end exit if result == {} result end def fill_items(dict, link_num=30) all_items = Array.new count = 0 # ユーザによってポストされたリンクを全て取得する src = nil dict.keys.each do |user| count += 1 3.times do |i| begin src = URI.parse("http://b.hatena.ne.jp/#{user}/rss").read break rescue puts "failed to get user's bookmark. retry(#{i+1})" sleep(5) next end end begin RSS::Parser.parse(src, false).items[0,link_num].each do |item| dict[user][item.link] = 1.0 all_items << item.link puts "#{count} : #{item.link}" end rescue puts "rss parse err. skipping : http://b.hatena.ne.jp/#{user}/rss" next end end # なかったアイテムは0をセットする dict.values.each do |items_h| all_items.each do |url| items_h[url] ||= 0.0 end end end if $0 == __FILE__ then require 'recommendation.rb' users = init_dict('rails') exit if users == {} users['ma2'] = Hash.new fill_items(users) puts '--- top_matches ---' top_matches(users,'ma2').each do |m| score = "%4.2f" % m[0] puts "#{score} : #{m[1]}" end recs = get_recommendations(users,'ma2')[0,10] if recs != [] puts '--- get_recommendations ---' recs.each do |r| puts "#{r[0]} : #{r[1]}" end end puts '--- get_recommendations(xformed) ---' if recs != [] url = get_recommendations(users,'ma2')[0][1] puts url top_matches(transform_prefs(users),url).each do |m| score = "%5.3f" % m[0] puts "#{score} : #{m[1]}" end end end
最後の方のユーザ名(ma2)とタグ名(rails)を書き換えてください。
ちなみにこれをやってみると,このままではブックマークはユーザ間で全然重なっていないことが分かる。ブックマークを取得する方法を工夫する必要があると思う。top_matchesのスコアはかなり低い。ただお勧めはけっこういいところをついてる気がする。ちなみに get_recommendations(xformed) の方は,人間中心ではなくて,アイテム中心で計算した結果です。この場合だと,お勧め URL の最初の 1 つをとって,これに近似した別の URL を探しています。実行結果は以下の通り。
--- top_matches ---
0.02 : toenobu
0.02 : sukesam
0.02 : moro-tyo
0.02 : miya2000
0.02 : ftnk
--- get_recommendations ---
0.4 : http://itpro.nikkeibp.co.jp/article/Watcher/20070924/282781/
0.4 : http://d.hatena.ne.jp/amachang/20071010/1192012056
0.4 : http://code.nanigac.com/
0.2 : https://www.google.com/accounts/ServiceLogin?service=sitemaps&passive=true&nui=1&continue=http%3A%2F%2Fwww.google.com%2Fwebmasters%2Ftools%2Fsiteoverview&followup=http%3A%2F%2Fwww.google.com%2Fw
ebmasters%2Ftools%2Fsiteoverview&hl=en
0.2 : https://jinmyaku-bank.cafe.rikunabi.com/
0.2 : http://youmos.com/news/cooltips
0.2 : http://www1.doshisha.ac.jp/~mjin/R/e_corpusR.html
0.2 : http://www1.bbiq.jp/kougaku/ARToolKit.html
0.2 : http://www004.upp.so-net.ne.jp/s_honma/probability/bayes.htm
0.2 : http://www.zentus.com/sqlitejdbc/
--- get_recommendations(xformed) ---
http://itpro.nikkeibp.co.jp/article/Watcher/20070924/282781/
0.57 : https://www.google.com/accounts/ServiceLogin?service=sitemaps&passive=true&nui=1&continue=http%3A%2F%2Fwww.google.com%2Fwebmasters%2Ftools%2Fsiteoverview&followup=http%3A%2F%2Fwww.google.com%2F
webmasters%2Ftools%2Fsiteoverview&hl=en
0.57 : https://jinmyaku-bank.cafe.rikunabi.com/
0.57 : http://www1.doshisha.ac.jp/~mjin/R/e_corpusR.html
0.57 : http://www.technobahn.com/cgi-bin/news/read2?f=200709222351&page=2
0.57 : http://www.prezvision.com/