Rubyで書くピアソン相関

前回のユークリッド距離に続いて「ピアソン相関によるスコア」です.

ピアソン相関の計算

正しくは,ピアソンの積率相関係数というらしいです.
巻末のp.342にある定義をそのまま実装しました.
sum_xy(x*yの部分和)を求めるのに,zipで書いてあるところがちょっと分かりにくいかもしれません.
なお,sqrtを使うにはMathモジュールが必要です.
お忘れなく.

require 'mathn'
include Math

module My
  class Recommender
    #
    # 任意の2人のピアソン相関を算出する
    #
    def get_pearson_correlation(critics, person1, person2)
      # 2人が批評している映画を抽出
      movies = critics[person1].keys & critics[person2].keys
      return 0 if movies.empty?

      # 映画ごとの評価値を得る
      critics_person1 = movies.map { |movie| critics[person1][movie] }
      critics_person2 = movies.map { |movie| critics[person2][movie] }

      get_pearson(critics_person1, critics_person2)
    end

    private

    #
    # ピアソン相関定義
    #
    def get_pearson(x, y)
      n = x.size
      sum_x = x.inject(0) { |sum, i| sum + i }
      sum_y = y.inject(0) { |sum, i| sum + i }
      sum_x_square = x.inject(0) { |sum, i| sum + (i ** 2) }
      sum_y_square = y.inject(0) { |sum, i| sum + (i ** 2) }
      sum_xy = x.zip(y).inject(0) { |sum, i| sum + (i.first * i.last) }

      numerator = sum_xy - (sum_x * sum_y.quo(n))
      denominator = sqrt((sum_x_square - (sum_x ** 2).quo(n)) * (sum_y_square - (sum_y ** 2).quo(n)))

      denominator == 0 ? 0 : numerator.quo(denominator)
    end
  end
end

実行結果

以下のように呼び出す部分を足して,実行してみます.

recommender = My::Recommender.new
puts recommender.get_pearson_correlation(critics, 'Lisa Rose', 'Gene Seymour')

いざ,実行!

% ./recommender.rb
0.39605901719067

本文のp.14と同じ結果が得られました.