WARNING:这是七年前的一篇文章…这个方法不适用于大量数据,仅仅是提供一种使用SVD的思路.
某天,一群《Family Guy》的粉丝们聚在一起,决定创建一个网站来分享各自喜欢的电视和对他们的评分,不久之后他们就获得了一个不错的网站,然后又有一大群人蜂拥而至和他们一起评分、分享,互相推荐电视剧集. 但由于用户越来越多,逐个查看某个人的评分记录,给她推荐电影越来越费事儿. 于是有人提出应该使用所有人的集体智慧来为每一个单独的人提供建议,这个过程应该是自动化的.
是不是看起来很熟悉?没错,这就是推荐系统的雏形.现在已经有了无数的论文描述如何通过复杂的算法来实现推荐系统,但目前为止最有效、最常用同时也是最简单的方法是: 奇异值分解(SVD), 也常被用于潜在语义索引和降维处理.
线性代数背景知识
SVD的背景知识可以简单描述为以下内容:
任何一个MxN的矩阵A,如果它的行数M大于或等于它的列数N,那么它就可以被转换成以下三个矩阵的乘积:一个MxM的正交矩阵U, 一个MxN的对角矩阵W(奇异值矩阵), 和一个正交矩阵V的转置矩阵.
更直观的说,如果我们有一个矩阵,每一行代表一个产品, 每一行中的所有用户对该产品的评分. 因此我们有了M个产品,N个用户的矩阵MxN.根据上面的理论,我们可以把这个矩阵分解为 MxM 的矩阵U, MxN 的奇异值矩阵S和 NxN 的矩阵V. 最棒的是,我们可以通过S矩阵的前几个奇异值就可以接近原来的MxN的矩阵了,而不必取完整的S(数学原理).
与机器学习的关系
机器学习最基本的一项功能就是用少量的字节尽可能接近的表示大量数据(如用户的聚类等).SVD正好给我们提供了通过少两字节表示大数据的功能,方式就是把数据投影到更小的维度上.
SVD最初在LSI(潜在语义索引)上大量使用,在这种场景下,每一行表示一个文档,行中的所有列表示每一个词.通过SVD我们可以可以找到那些关联度比较大的项(比如那些经常同时出现的词),把这些关联度比较大的词作为一个特征(这就达到了降维的目的).最终的目的就可以把那些不重要的噪声去掉,只保留有用的信息.实践中做信息检索的人通常会把10000+的维度降到几百. 同样的方法也可以用在图像压缩和计算机视觉应用上.
降维
回到我们最初的电视剧问题.简单起见,我们用6个电视剧剧集和4个用户组成矩阵(6×4矩阵).然后把这个矩阵使用SVD分解成三个小矩阵,U(6×6), S(6×4), V(4×4),为了简单起见,我们只取每个矩阵的前两列:
现在我们有了二维的数据,可以把结果画出来了. 我们把U的第一列作为x轴,第二列作为y轴可以画出不同的电视剧集的分布图.同样可以画出V的分布以表示用户的分布.
我们可以看到两个用户非常像(当然用户太少,称他们为cluster有点言过其实),当用户越来越多的时候聚类就越来越明显.从图中我们可以看出Ben和Fred的品味很像.
找到相似用户
现在,新用户Bob进来了,然后对一些剧集做了评分([5,5,0,0,0,5] for seasons 1-6) – 我们现在需要根据这些新数据给他做推荐.直观上来看,我们需要找到跟Bob相似的用户, 如果我们能把Bob插入到我们的二维空间,就可以找到谁跟他相似了,为了实现这点,我们需要进行以下的计算:
通过简单地矩阵计算,我们就可以把Bob投影到二维空间,具体的数学原理可以在上面提到的线性代数参考资料中看到. 现在我们把Bob添加到我们的图中:
现在我们就可以通过一系列相似性算法,如余弦相似度来计算Bob与谁最接近了.通过余弦相似度我们发现Ben与Bob最接近.