2章 その4

今回は関数ポインタが出てくるので、rubyのObject#method関数を使った
http://www.ruby-lang.org/ja/man/html/Method.html



全ての人の中から趣向の近い人を求める。全員との相関を計算して、相関係数の高い人から順に並べる。
これまで相関計算方法を2つやったので、高階関数を用いてどちらの相関計算方法を使うか選べるようにする。(今回はObject#methodという機能を使った)
p.15より recommendations.rb にtomMatches関数を追加した
長くなったので全文はこっち http://www.bitbucket.org/shokai/collective-intelligence-study/src/b932f951ea2c/recommendations.rb

  # ディクショナリprefsからpersonにもっともマッチするものたちを返す
  # 結果の数と類似性関数はオプションのパラメータにする
  def topMatches(prefs, person, n=5, similarity=:sim_pearson)
    
    # 得点:ユーザ名 のhashを作る
    scores = Hash.new
    prefs.keys.each{ |other|
      if other != person
        scores[self.method(similarity).call(prefs, person, other)] = other
      end
    }
    
    # 高スコアがリストの最初に来るように並び替えた配列を作る
    result = Array.new
    scores.keys.sort.reverse.each{ |score|
      result.push({ score => scores[score] })
    }
    
    
    # 0~n番目の結果だけ結果を返す
    return result[0..n-1]
  end

実行してみる。ユーザ名Tobyで3件、趣向が近い順に出力。
irb -r recommendations.rb

>> c = Critics.new
=> #<Critics:0x695ba4 @users={"Jack Matthews"=>{"The Night Listener"=>3.0, "Superman Returns"=>5.0, "Lady in the Water"=>3.0, "Snake on a Plane"=>4.0, "You, Me and Dupree"=>3.5}, "Gene Seymour"=>{"The Night Listener"=>3.0, "Superman Returns"=>5.0, "Lady in the Water"=>3.0, "Snake on a Plane"=>3.5, "You, Me and Dupree"=>3.5, "Just My Luck"=>1.5}, "Mick LaSalle"=>{"The Night Listener"=>3.0, "Superman Returns"=>3.0, "Lady in the Water"=>3.0, "Snake on a Plane"=>4.0, "You, Me and Dupree"=>2.0, "Just My Luck"=>2.0}, "Toby"=>{"Superman Returns"=>4.0, "Snake on a Plane"=>4.5, "You, Me and Dupree"=>1.0}, "Claudia Puig"=>{"The Night Listener"=>4.5, "Superman Returns"=>4.0, "Snake on a Plane"=>3.5, "You, Me and Dupree"=>2.5, "Just My Luck"=>3.0}, "Lisa Rose"=>{"The Night Listener"=>3.0, "Superman Returns"=>3.5, "Lady in the Water"=>2.5, "Snake on a Plane"=>3.5, "You, Me and Dupree"=>2.5, "Just My Luck"=>3.0}, "Michael Phillips"=>{"The Night Listener"=>4.0, "Superman Returns"=>3.5, "Lady in the Water"=>2.5, "Snake on a Plane"=>3.0}}>
>> c.topMatches(c.users, 'Toby', n=3)
=> [{0.99124070716193=>"Lisa Rose"}, {0.924473451641905=>"Mick LaSalle"}, {0.893405147441565=>"Claudia Puig"}]

上では計算方法は指定していないが、しないとピアソン法になるように関数を定義してある。


別のユーザでユークリッド距離法で4件出してみたところ

>> c.topMatches(c.users, 'Lisa Rose', 4, :sim_distance)
=> [{0.444444444444444=>"Michael Phillips"}, {0.333333333333333=>"Mick LaSalle"}, {0.285714285714286=>"Claudia Puig"}, {0.222222222222222=>"Toby"}]