代码之家  ›  专栏  ›  技术社区  ›  rel1x

使用SVD矩阵进行预测

  •  4
  • rel1x  · 技术社区  · 10 年前

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

    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 lang获取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 回复  |  直到 10 年前
        1
  •  6
  •   Marc in the box    10 年前

    在我看来,你的例子有几点不正确。首先,当您没有特定用户/电影组合的可用排名时,则不应将其填充为零。这将告诉SVD或任何其他类型的主成分分析(PCA),这些是排名(人为较低)。此外,用零填充数据计算的协方差将基于不正确的观测数量计算。

    Netflix奖得主( link for more info )使用SVD方法的也必须使用某种缺失数据PCA例程。在这种情况下,非值不应为零,而是 NaN ,尽管我还没有看到他们使用的实际方法的细节。

    我的第二个问题是,您提供的“答案”是否真的基于您在示例中提供的相当小的数据集。给定3个用户乘3个电影数据集,用于计算用户之间相关性的位置非常少,因此任何预测都将非常差。尽管如此,我还是得出了一个结果,但它与你的预期答案不符。

    该方法被称为“递归减去经验正交函数”(RSEOF),是专门设计的PCA方法,用于处理缺失数据。也就是说,如果没有更大的训练数据集,我不会对预测有太多信心。

    因此,我首先加载原始数据集和预测数据集,然后使用 acast 来自 reshape2 包裹:

    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
    

    然后使用 eof 的功能 sinkr 包装( 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
    

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

    # 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。

    我希望这对你有所帮助——但是,如果你的预期答案是你想要的,那么我会怀疑“真相持有者”所使用的方法。更可能的是,您只是提供了数据集的一个较小版本,因此我们不会得出与您的较小可复制示例相同的答案。

        2
  •  3
  •   vrume21    10 年前

    这是一个经典的矩阵完成问题,我们将数据矩阵中的未知值替换为零。您需要首先对数据矩阵进行本征分解(因为它是对称的,但SVD是等效的,请注意U==V)。然后得到A_pred=UEU^T,其中A_pred是A(数据矩阵)的预测完整版本。因此,A[i][j]的预测值简单地为A_pred[i][j]。