使用SVD矩阵进行预测

4

我正在参加编程比赛,其中我有一些数据,第一列是用户,第二列是电影,第三列是十分制评分系统中的数字。

0 0 9
0 1 8
1 1 4
1 2 6
2 2 7

我需要预测第三列(用户,电影,?):

0 2
1 0
2 0
2 1

此外,我知道答案:

0 2 7.052009
1 0 6.687943
2 0 6.995272
2 1 6.687943

这是一个表格数据:行代表用户0、1和2;列代表电影0、1和2;单元格中的数字表示得分,0表示未投票:
     [,1] [,2] [,3]
[1,]    9    8    0
[2,]    0    4    6
[3,]    0    0    7

我使用R语言进行奇异值分解(SVD):

$d
[1] 12.514311  9.197763  2.189331

$u
          [,1]       [,2]       [,3]
[1,] 0.9318434 -0.3240669  0.1632436
[2,] 0.3380257  0.6116879 -0.7152458
[3,] 0.1319333  0.7216776  0.6795403

$v
          [,1]        [,2]       [,3]
[1,] 0.6701600 -0.31709904  0.6710691
[2,] 0.7037423 -0.01584988 -0.7102785
[3,] 0.2358650  0.94825998  0.2125341

转置后的v是:

          [,1]        [,2]       [,3]
[1,]  0.6701600   0.7037423   0.2358650
[2,] -0.31709904 -0.01584988  0.94825998
[3,]  0.6710691  -0.7102785   0.2125341

我了解到可以使用以下公式来预测电影评分: enter image description here

但我不明白如何用这种方式来预测评分:

0 2 7.052009
1 0 6.687943
2 0 6.995272
2 1 6.687943

对于这个数据:

0 2
1 0
2 0
2 1
2个回答

6
你的例子中有几个地方我觉得不正确。首先,当你没有一个特定用户/电影组合的排名时,你不应该用零填充它。这会告诉SVD或任何其他类型的主成分分析(PCA)这些是排名(人为降低)。此外,使用零填充数据计算的协方差将基于不正确的观察数量进行计算。
使用SVD方法的Netflix奖获得者(link for more info)也必须使用某种缺失数据PCA程序。在这种情况下,非值不应该是零,而应该是NaN,尽管我还没有看到他们使用的实际方法的详细信息。
我有第二个问题,即你提供的“答案”是否真的基于你在示例中给出的相当小的数据集。鉴于3个用户和3个电影的数据集,计算用户之间的相关性的位置非常少,因此任何预测都将非常糟糕。尽管如此,我能够产生一个结果,但它与你期望的答案不符。
这种方法被称为“递归减去经验正交函数”(RSEOF),是一种专门设计用于处理缺失数据的PCA方法。话虽如此,如果没有更大的训练数据集,我对预测结果并不太有信心。
因此,我从加载原始数据和预测数据开始,并使用reshape2包中的acast将训练数据重新塑造成矩阵形式:
library(reshape2)
library(sinkr) (download from GitHub: https://github.com/menugget/sinkr)

# Original data
df1 <- data.frame(user=factor(c(0,0,1,1,2)), movie=factor(c(0,1,1,2,2)), rank=c(9,8,4,6,7))
df1

# Data to predict
df2 <-data.frame(user=factor(c(0,1,2,2)), movie=factor(c(2,0,0,1)))
df2

# Re-organize data into matrix(movies=rows, users=columns)
m1 <- acast(df1, movie ~ user, fill=NaN)
m1

然后使用 sinkr 包的 eof 函数(link)进行 RSEOF 操作:
# PCA of m1 (using recursive SVD)
E <- eof(m1, method="svd", recursive=TRUE, center=FALSE, scale=FALSE)
E$u
E$A #(like "v" but with Lambda units added)
E$Lambda

可以通过使用PCA信息重新构建完整矩阵(基本上是 E$A %*% t(E$u))来获得数据中NaN位置的预测值:

# Reconstruct full m1 matrix using PCs
R <- eofRecon(E)
R

# Add predicted ranks to df2
pos <- (as.numeric(df2$user)-1)*length(levels(df1$movie)) + as.numeric(df2$movie)
pos
df2$rank <- R[pos]
df2

对象df2包含了您在预测数据集中指定的用户/电影组合的特定预测排名:

  user movie     rank
1    0     2 9.246148
2    1     0 7.535567
3    2     0 6.292984
4    2     1 5.661985

我个人认为这些值比您期望的结果更有意义(所有值都在7左右)。例如,在查看电影矩阵(行)和用户矩阵(列)时,m1
    0   1   2
0   9 NaN NaN
1   8   4 NaN
2 NaN   6   7

我期望用户“0”会更喜欢电影“2”而不是电影“1”,因为这是用户“1”的趋势。我们只有电影“1”的排名可以用来预测。你的期望值是7.05,低于电影“1”的期望值(即8),而RSEOF预测值为9.2。
希望这可以帮到你,但如果你期望的答案就是这个,那么我对“真相持有者”使用的方法表示怀疑。更有可能的是,你只是提供了数据集的较小版本,因此我们无法得出与你的较小可重现示例相同的答案。

首先,当您没有特定用户/电影组合的排名可用时,您不应该将其填充为零。这是错误的:这是矩阵完成任务中采取的标准方法。请参阅有关此主题的任何参考资料(包括维基百科)。 - vrume21
@vrume21 - 我想你搞错了。只有在对矩阵进行居中处理之后,才可以替换零值。如果此前这样做,那么它们将会严重扭曲加权结果。与之等价的方法是用每个变量的均值来替代缺失值。 - Marc in the box

3

这是一个经典的矩阵补全问题,我们需要在数据矩阵中用0替换未知值。首先需要对数据矩阵进行特征值分解(因为它是对称的,但SVD也是等效的,注意U == V)。然后你就有了A_pred = UEU^T,其中A_pred是A(你的数据矩阵)的预测完整版本。因此,A[i][j]的预测值简单地是A_pred[i][j]。


你不明白什么? - vrume21
我的下一步应该是什么?可以展示一下如何使用我的数据来预测评分的例子吗? - rel1x
你已经计算出了A_pred,因为你已经进行了SVD。你需要预测的评分是A中值为零的评分,所以你在A和A_pred中有它们的索引。对于每一对索引(I,j),预测的评分是A_pred[i][j]。 - vrume21
该方法仅预测原矩阵中的0。例如:m <- matrix(c(9,0,0,8,4,0,0,6,7),3,3); S <- svd(m); zapsmall(S$u%*%diag(S$d)%*%t(S$v)) - Marc in the box
当然,这些是该操作所要预测的唯一值。 - vrume21
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接