自分がフォローしている人たちだけのbuzztterみたいなものを実現する with Echofon
先日中川さん(id:Psychs)によってEchofon for Macのベータ版がnaan studioからリリースされました。
http://echofon.com/twitter/mac/
http://d.hatena.ne.jp/Psychs/20091001/1254351633
必要な機能をシンプルにまとめたTwitterクライアントでとても使いやすいです。(個人的にはあとjk移動がほしい)
さてEchofonはTwitterのログを保存する際にSQLiteを使っているのが一つの特徴です。
そのため自分の過去ログをいじっていろんなことができておもしろいです。
例えば自分がフォローしている人たちだけを対象にしたbuzztterみたいなことを実現することができます。
(Twitter日本語圏全体からのホットなキーワード抽出として、ぼくは@yazztterというのを作っています:))
具体的には自分のまわりで直近1時間で話題になっているキーワード(特徴語)を抽出したりできます。
O/RマッパーとしてActiveRecord, 形態素解析器としてMeCabを使ってRubyで書くと下のようになります。
$KCODE = 'u' require 'rubygems' require 'active_record' require 'MeCab' ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :dbfile => '/Users/username/Library/Application Support/Echofon/tweets_db.sql' #usernameを自分の環境に合わせて変更 ) class Status < ActiveRecord::Base end def calculate_statuses_tfidf t = Time.now.strftime('%s').to_i #現在時刻をEchofonに合わせてUNIX時間に変換 all_statuses = [] recent_statuses = [] past_time = 24 #とりあえず24時間前までのログを過去ログの対象とする (1..past_time).each do |i| lower_limit = t - 3600 * i upper_limit = t - 3600 * (i - 1) statuses = Status.find(:all, :conditions => ['created_at >= ? and created_at < ?', lower_limit, upper_limit]) word_count = Hash.new(0) statuses.each do |st| st.text.split(/,、。 /).each do |s| #句読点や半角スペースと全角スペースがあったらそこでいったん区切る c = MeCab::Tagger.new n = c.parseToNode(s) words = '' while n do #抽出する単語を名詞や記号などに限定して、それらが連続していればくっつける if (n.feature.split(',').first == '名詞') || (n.feature.split(',')[1] == '連体化') || ((n.feature.split(',').first == '記号') && (n.feature.split(',')[1] == '一般')) words += n.surface else if words != '' word_count[words] += 1 words = '' end end n = n.next end end end recent_statuses = word_count.to_a if i == 1 all_statuses << word_count.to_a end result = [] recent_statuses.sort{|a, b| b[1] <=> a[1]}.each do |w| break if w.last < 3 #1時間以内の発言数が3未満の単語は対象外とする tf = w.last df = all_statuses.flatten(1).select{|i| i.first == w.first}.size #ruby 1.8.7以上からflattenに引数をとれるようになった! idf = Math::log(past_time / df.to_f) tfidf = tf * idf result << [w.first, tfidf] end result.sort {|a, b| b[1] <=> a[1]} end if __FILE__ == $0 calculate_statuses_tfidf.each do |i| puts i.first + ': ' + i.last.to_s end end
コードを読んでもらえれば大体どんなことをやっているか分かると思いますが、tf-idfというキーワード抽出のためのアルゴリズムを使っています。tf-idfとは簡単に言ってしまえば、ある文書中によく出てくる単語にはキーワードになりそうなので高スコアを割り当てたいけれども、その単語が他の文書中にも出てくるようならばそれはキーワードというよりも一般的な単語と見なせるのでその分スコアを差し引く、という考え方です。
参考: [を] 形態素解析と検索APIとTF-IDFでキーワード抽出
今回は1時間ごとのログを1つの文書とし、24時間分なので全体で24の文書があるとしてtf-idfを適用しています。
ログがあれば48時間分とかにしたほうがもう少し正確なキーワード抽出ができるかもしれません。
Twitterクライアントは常時起動しているとは限らないのでどうしても取りこぼしなどが出てきてしまうのは仕方のないことですが、ログをきちんと保存するクライアントであれば、今回紹介したEchofonではなくても上記と同様の手法が適用できると思うので試したりしてください!