2.4 アイテムを推薦する

今度はgetRecommendations関数を移植する。
ただし、id:shrkw:20081113:cloud_on_pci_1 でも

最後にそのアイテムを評価しているユーザーの類似度の計で除算するというのが理解できない。

と指摘されているように、評点の合計で割るというのは違和感があるので、ここでは平均値を使うことにする。
そのためサンプルコードとは結果が異なっている。
この評点の合計で割るというのは本文中では「正規化」と表現されているので、もしかしたら前述した個人差を補正するような意図で行われているのかも知れない。
だとしても謎であるが。

# 指定した評者に次に見るべき作品のリストを出す関数。
# prefs      行が作品、列が評者のマトリクス
# person     対象者
# similarity 類似性の指標。既定値はピアソンの積率相関係数。
#            "euclidean"	ユークリッド平方距離
#            "euclidean.center"	評者ごとに中心化したユークリッド平方距離
#            "manhattan"	マンハッタン距離
#            "manhattan.center"	評者ごとに中心化したマンハッタン距離
#            "pearson"	ピアソンの積率相関係数
#            "spearman" 	スピアマンの順位相関係数
#            "kendall" 	ケンドールの順位相関係数
getRecommendations <- function(prefs, person, similarity="pearson"){
    switch(similarity,
        "euclidean" = sim.index <- as.matrix(1/(1+dist(t(prefs))^2)),
        "euclidean.center" = sim.index <- as.matrix(1/(1+dist(t(scale(prefs, scale=FALSE)))^2)),
        "manhattan" = sim.index <- as.matrix(1/(1+dist(t(prefs), method="manhattan"))),
        "manhattan.center" = sim.index <- as.matrix(1/(1+dist(t(scale(prefs, scale=FALSE)), method="manhattan"))),
        "pearson" = sim.index <- cor(prefs, use="pairwise.complete.obs"),
        "spearman" = sim.index <- cor(prefs, use="pairwise.complete.obs", method="spearman"),
        "kendall" = sim.index <- cor(prefs, use="pairwise.complete.obs", method="kendall")
        )
    diag(sim.index) <- 0
    # ここから下はもうちょっとキレイに書けそうな気がするけど……
    x1 <- (sim.index[,colnames(sim.index)==person])
    x2 <- x1[names(x1)!=person]
    x3 <- x2[x2>0]
    y1 <- prefs[,colnames(prefs)!=person]
    y2 <- y1[,x2>0]
    z1 <- apply(as.matrix(x3*y2), 1, mean, na.rm=TRUE)
    z2 <- prefs[,colnames(prefs)==person]
    sort(z1[is.na(z2)], decreasing=TRUE)
    }

使い方。データと評者と類似性の指標を指定するだけ。

getRecommendations(critics, "Toby", "spearman")
# 出力
#  Lady.in.the.Water       Just.My.Luck The.Night.Listener 
#           2.587713           2.532692           1.687500