集合知プログラミングの勉強(5)
getRecommendation を R でも実装しようとしてしばらく苦戦。ハッシュテーブルなんてものは R には無い?
ふっと、表2-2 筆者のための推薦の作成 の表そのものを、データフレームとして作ればいいことに気付く。R はモダーンな言語で、関数を引数にするなんてことは余裕でできるのだった。
f1 <- function(person) { prefs <- data1.load() prefs["sim"] <- sapply(prefs$Person, function(other) { sim.pearson(prefs, person, other) }) # prefs["S.xNight"] <- prefs$sim * m$Night.Listener prefs }
対話的環境だとこのようになる。Rose に対する推薦の表、Toby に対する推薦の表。
> f1("Rose") Person Night.Listener Dupree Superman Just.My.Luck Snakes Lady sim 1 Rose 3.0 2.5 3.5 3.0 3.5 2.5 1.0000000 2 Seymour 3.0 3.5 5.0 1.5 3.5 3.0 0.3960590 3 Phillips 4.0 NA 3.5 NA 3.0 2.5 0.4045199 4 Puig 4.5 2.5 4.0 3.0 3.5 NA 0.5669467 5 LaSalle 3.0 2.0 3.0 2.0 4.0 3.0 0.5940885 6 Matthews 3.0 3.5 5.0 NA 4.0 3.0 0.7470179 7 Toby NA 1.0 4.0 NA 4.5 NA 0.9912407 > f1("Toby") Person Night.Listener Dupree Superman Just.My.Luck Snakes Lady sim 1 Rose 3.0 2.5 3.5 3.0 3.5 2.5 0.9912407 2 Seymour 3.0 3.5 5.0 1.5 3.5 3.0 0.3812464 3 Phillips 4.0 NA 3.5 NA 3.0 2.5 -1.0000000 4 Puig 4.5 2.5 4.0 3.0 3.5 NA 0.8934051 5 LaSalle 3.0 2.0 3.0 2.0 4.0 3.0 0.9244735 6 Matthews 3.0 3.5 5.0 NA 4.0 3.0 0.6628490 7 Toby NA 1.0 4.0 NA 4.5 NA 1.0000000 >
あとはそれぞれのタイトル毎に、sim をかけ算してやればいい。本文では、python コードを「非常に理解しやすい」と書いているが、ひょっとすると、分かりやすさという点で R はそれ以上かもしれない。
なんとか getrecommendation を実装。もっとエレガントに書けると思えるがとりあえず。まだ R の基本も分かっていないことが、プログラムを書いたら良くわかった。
> getrecommendations("Toby") Night Lady Luck 3.347790 2.832550 2.530981
# データフレーム prefs に対し、 # person 以外について、 類似性と S.x タイトル の値を計算したデータフレームを返す data1.sim <- function(prefs, person) { titles <- colnames(prefs)[2:length(prefs)] sxtitles <- sapply(titles, function(title) { paste("S.x", title, sep="") }) ## sim を計算 prefs["sim"] <- sapply(prefs$Person, function(other) { sim.pearson(prefs, person, other) }) for (i in 1:length(titles)) { title <- titles[i] sxtitle <- sxtitles[i] prefs[sxtitle] <- prefs["sim"] * prefs[title] } # 自分以外 subset(prefs, prefs$Person != person) } getrecommendations <- function(person) { prefs <- data1.load() sims <- data1.sim(prefs, person) # sim, S.x の列を追加したデータを生成 # 見ていないタイトル一覧を作成 whos <- scores.for(prefs, person) titles <- rownames(subset(whos, is.na(whos[,1]))) # 見ていないタイトル全てに対して S.x列の合計を計算 totals <- sapply(titles, function(title) { sxtitle <- paste("S.x", title, sep="") scores <- sims[sxtitle] scores <- scores[scores > 0] # 必要。 sum(scores, na.rm=TRUE) }) ## 見ていないタイトル全てに対して、その映画を見た評者の類似度の合計を計算 sim.sum <- sapply(titles, function(title) { sxtitle <- paste("S.x", title, sep="") sims.ex <- sims[ ! is.na(sims[title]),] sim <- sims.ex["sim"] sim <- sim[sim > 0] sim.sum <- sum (sim, na.rm=TRUE) sim.sum }) ## result <- totals/sim.sum ## ソート sorted <- order(result, decreasing=TRUE) result[sorted] }