10 月 19 2008
[Ruby] 集合知プログラミング 03
オライリー「集合知プログラミング」のPythonサンプルコードをRubyに翻訳していく作業ログ。3回目。
2.3.4 評者をランキングするのサンプルコードをRuby化
def top_matches( prefs, person, n=5, similarity=:sim_pearson)
scores = prefs.keys.select{|i| i != person}.map do |other|
[ method(similarity).call(prefs,person,other), other ]
end
return scores.sort.reverse[0...n]
end
p top_matches( critics, 'Toby', 3 )
# => [[0.99124070716193, "Lisa Rose"], [0.924473451641905, "Mick LaSalle"], [0.66284898035987, "Claudia Puig"]]
scores = prefs.keys.select{|i| i != person}.map do |other|
[ method(similarity).call(prefs,person,other), other ]
end
return scores.sort.reverse[0...n]
end
p top_matches( critics, 'Toby', 3 )
# => [[0.99124070716193, "Lisa Rose"], [0.924473451641905, "Mick LaSalle"], [0.66284898035987, "Claudia Puig"]]
2.4 アイテムを推薦するのサンプルコードをRuby化
def get_recommendations( prefs, person, similarity=:sim_pearson )
totals = {}
sim_sums = {}
prefs.keys.each do |other|
# 自分自身とは比較しない
next if other == person
sim = method(similarity).call( prefs, person, other )
# 0以下のスコアは無視
next if sim <= 0
prefs[other].each do |item|
item_name = item[0]
# まだ見てない映画の得点のみ算出
if !prefs[person].key?(item_name) or prefs[person][item_name] == 0
# 類似度 * スコア
totals[item_name] ||= 0
totals[item_name] += prefs[other][item_name] * sim
# 類似度を合計
sim_sums[item_name] ||= 0
sim_sums[item_name] += sim
end
end
end
# 正規化したリストを作る
rankings = []
totals.each do |item_name,total|
rankings <<[ total / sim_sums[item_name], item_name ]
end
# ソート済みのリストを返す
return rankings.sort.reverse
end
p get_recommendations( critics, 'Toby' )
# => [[3.27445961524987, "The Night Listener"], [2.95467531335197, "Lady in the Water"], [2.34855517312818, "Just My Luck"]]
totals = {}
sim_sums = {}
prefs.keys.each do |other|
# 自分自身とは比較しない
next if other == person
sim = method(similarity).call( prefs, person, other )
# 0以下のスコアは無視
next if sim <= 0
prefs[other].each do |item|
item_name = item[0]
# まだ見てない映画の得点のみ算出
if !prefs[person].key?(item_name) or prefs[person][item_name] == 0
# 類似度 * スコア
totals[item_name] ||= 0
totals[item_name] += prefs[other][item_name] * sim
# 類似度を合計
sim_sums[item_name] ||= 0
sim_sums[item_name] += sim
end
end
end
# 正規化したリストを作る
rankings = []
totals.each do |item_name,total|
rankings <<[ total / sim_sums[item_name], item_name ]
end
# ソート済みのリストを返す
return rankings.sort.reverse
end
p get_recommendations( critics, 'Toby' )
# => [[3.27445961524987, "The Night Listener"], [2.95467531335197, "Lady in the Water"], [2.34855517312818, "Just My Luck"]]
引数similarityで、使用する類似性関数を切り替える。Rubyでは
method(:method_name).call
というような形で、シンボルまたは文字列でメソッド名を指定することでメソッドをコールできます。 http://www.ruby-lang.org/ja/man/html/Object.html#method
オリジナルのPythonのサンプルコードではタプルオブジェクトが多用されているが、Rubyでは配列に置き換えている。