如何在协同过滤中使用 SVD?

机器算法验证 svd 推荐系统
2022-01-15 20:30:42

我对如何在协同过滤中使用 SVD 感到有点困惑。假设我有一个社交图,我从边缘构建一个邻接矩阵,然后采用 SVD(让我们忘记正则化、学习率、稀疏优化等),我如何使用这个 SVD 来改进我的推荐?

假设我的社交图对应于 instagram,我的任务是仅根据社交图推荐服务中的用户。我会先建立一个邻接矩阵,取 SVD,,选择前个特征值,然后呢?A (m×m)A=UsVk

我大概会创建一组新的矩阵: 那么一个人做了什么?

Unewm×ksnewk×kVnewk×m

我在网上看过,大多数链接都集中在计算 SVD,但没有人告诉你如何处理它。所以我该怎么做?

4个回答

我想提出不同意见:

缺失边缘作为缺失值

在协同过滤问题中,不存在的连接(用户没有评价项目,人没有加好友)通常被视为要预测的缺失值,而不是零。也就是说,如果用户没有给项目,我们想猜测如果他给它打分,会给它打什么分。如果人还没有加好友,我们想猜测他加好友的可能性有多大。这些建议基于重构的值。ijxyijxy

当您获取社交图谱的 SVD 时(例如,将其插入svd()),您基本上是在所有那些缺失的点上归零。这在协同过滤的用户项目评级设置中更为明显。如果我有办法可靠地填写缺失的条目,我根本不需要使用 SVD。我只是根据填写的条目给出建议。如果我没有办法做到这一点,那么我不应该在执行 SVD 之前填写它们。*

具有缺失值的 SVD

当然,该svd()函数不知道如何处理缺失值。那么,你究竟应该怎么做?好吧,有一种方法可以将问题重新定义为

“找到最接近原始矩阵的秩为k

这确实是您要解决的问题,而且您不会用svd()它来解决它。对我有用的一种方法(在 Netflix 奖品数据上)是这样的:

  • 尝试用一个简单的模型拟合条目,例如这实际上做得很好。X^i,j=μ+αi+βj

  • 为每个用户分配一个向量 u_i ,为每个项目一个v_j (在您的情况下,每个人都会得到一个左右向量)。您最终将残差预测为点积:ikuijkvjkuimvjm

  • 使用一些算法来找到使与原始矩阵的距离最小的向量。例如,使用这篇论文

祝你好运!

* : Tenali 推荐的基本上是最近的邻居。您尝试找到相似的用户并就此提出建议。不幸的是,稀疏性问题(约 99% 的矩阵缺失值)使得使用余弦距离或 Jaccard 相似度或其他方法很难找到最近的邻居。因此,他建议对矩阵进行 SVD(在缺失值处填充零),首先将用户压缩到较小的特征空间中,然后在那里进行比较。做 SVD-nearest-neighbors 很好,但我仍然建议以正确的方式做 SVD(我的意思是......我的方式)。无需进行无意义的价值估算!

没有人告诉你如何处理它的原因是因为如果你知道 SVD 做什么,那么如何处理它就有点明显了:-)。

由于您的行和列是相同的集合,我将通过不同的矩阵 A 来解释这一点。让矩阵 A 使得行是用户,列是用户喜欢的项目。请注意,这个矩阵不一定是对称的,但在你的情况下,我猜它是对称的。考虑 SVD 的一种方法如下:SVD 找到一个隐藏的特征空间,其中用户和他们喜欢的项目具有紧密对齐的特征向量。

因此,当我们计算时,矩阵表示隐藏特征空间中用户对应的特征向量,矩阵表示隐藏特征空间中项目对应的特征向量。A=U×s×VUV

现在,如果我给你来自同一特征空间的两个向量,并要求你找出它们是否相似,你能想到的最简单的方法是什么?点积。

所以,如果我想看到用户喜欢项目,我需要做的就是取个条目个条目的点积。当然,点积绝不是你唯一的事情可以应用,你能想到的任何相似性度量都是适用的。ijiUj

但是:使用纯普通 SVD,您可能无法重新创建原始矩阵,更不用说预测缺失项的值了。该领域有用的经验法则是计算每部电影的平均评分,然后减去每个用户/电影组合的平均值,即减去每个用户的电影偏差。然后建议您运行 SVD,当然,您必须在某处记录这些偏差值,以便重新创建评级或预测未知值。我读过 Simon Funk 在 SVD 上的推荐文章——他在 Netflix 比赛中发明了一种增量 SVD 方法。

http://sifter.org/~simon/journal/20061211.html

我想在 SVD 之前贬低矩阵 A 是有道理的,因为 SVD 的近亲 PCA 也以类似的方式工作。在增量计算方面,Funk 告诉我,如果你不贬低,第一个梯度方向将主导其余的计算。我亲眼看到了这个,基本上没有贬低的东西是行不通的。

这是为那些想要实际实施稀疏 SVD 建议或检查源代码以获取详细信息的人尝试回答问题的“如何”部分。您可以使用现成的 FOSS 软件对稀疏 SVD 建模。例如,vowpal wabbitlibFMredsvd

vowpal wabbit有 3 种“类 SVD”算法的实现(每个都可以通过 3 个命令行选项之一进行选择)。严格来说,这些应该称为“近似、迭代、矩阵分解”而不是纯粹的“经典”SVD”,但它们与 SVD 密切相关。您可能认为它们是计算效率非常高的稀疏 SVD 分解(主要是零)矩阵。

这是一个完整的、有效的 Netflix 风格电影推荐方法,vowpal wabbit它的“低级二次”( --lrq) 选项似乎最适合我:

数据集格式文件ratings.vw(用户和电影每行评分):

5 |user 1 |movie 37
3 |user 2 |movie 1019
4 |user 1 |movie 25
1 |user 3 |movie 238
...

其中第一个数字是评分(1 到 5 星),后跟评分的用户 ID 和评分的电影 ID。

测试数据的格式相同,但可以(可选)省略评级列:

 |user 1 |movie 234
 |user 12 |movie 1019
...

可选地,因为要评估/测试预测,我们需要评级来比较预测。如果我们省略评分,vowpal wabbit仍会预测评分,但无法估计预测误差(数据中的预测值与实际值)。

为了训练,我们要求在用户和他们喜欢(或不喜欢)的电影之间vowpal wabbit找到一组潜在的交互因素。N您可能会认为这是找到相似用户以相似方式对电影子集进行评分的常见主题,并使用这些常见主题来预测用户如何评价他尚未评分的电影。

vw我们需要使用的选项和参数:

  • --lrq <x><y><N>找到“低等级二次”潜在因素。
  • <x><y>: "um" 表示跨越数据集中的 u[sers] 和 m[ovie] 命名空间。请注意,只有每个命名空间中的第一个字母与该--lrq选项一起使用。
  • <N>N=14下面是我们想要找到的潜在因素的数量
  • -f model_filename: 将最终模型写入model_filename

因此,一个简单的完整训练命令将是:

    vw --lrq um14 -d ratings.vw -f ratings.model

一旦我们有了ratings.model模型文件,我们就可以用它来预测新数据集的额外评级more_ratings.vw

    vw -i ratings.model -d more_ratings.vw -p more_ratings.predicted

预测将被写入文件more_ratings.predicted

demo/movielens在源代码树中使用,在对具有 14 个潜在因素vowpalwabbit的 100 万个用户/电影评分进行训练ml-1m.ratings.train.vw(意味着 SVD 中间矩阵是 14x14 行 x 列矩阵)并在独立测试集ml-1m.ratings.test.vw0.69 MAE 有多好?对于所有可能的预测范围,包括未评级 (0) 的情况 [0 到 5],0.69 的误差是整个范围的 ~13.8% (0.69/5.0),即大约 86.2% 的准确度 (1 - 0.138)。

vowpal wabbit您可以在 github的源代码树中找到类似数据集 (movielens) 的示例和完整演示,其中包含文档:

笔记:

  • movielens演示使用了我在示例中省略的几个选项(为简单起见):特别是--loss_function quantile--adaptive--invariant
  • 中的--lrq实现比 中vw的快得多--rank,尤其是在存储和加载模型时。

学分:

  • --rankvw 选项由 Jake Hofman 实现
  • --lrqvw 选项(可选 dropout)由 Paul Minero 实现
  • vowpal wabbit (aka vw) 是 John Langford 的大脑孩子