餐馆可划分为很多类别,比如美式、中式、日式、牛排馆、素食店,等等。你是否想过这些
类别够用吗?或许人们喜欢这些的混合类别,或者类似中式素食店那样的子类别。如何才能知道
到底有多少类餐馆呢?我们也许可以问问专家?但是倘若某个专家说应该按照调料分类,而另一
个专家则认为应该按照配料分类,那该怎么办呢?忘了专家,我们还是从数据着手吧。我们可以
对记录用户关于餐馆观点的数据进行处理,并且从中提取出其背后的因素。
    这些因素可能会与餐馆的类别、烹饪时所用的某个特定配料,或其他任意对象一致。然后,
我们就可以利用这些因素来估计人们对没有去过的餐馆的看法。提取这些信息的方法称为奇异值分解(Singular Value Decomposition, SVD)。从生物信息学到金融学等在内的很多应用中,SVD都是提取信息的强大工具。
    本章将介绍SVD的概念及其能够进行数据约简的原因。然后,我们将会介绍基于Python的
SVD实现以及将数据映射到低维空间的过程。再接下来,我们就将学习推荐引擎的概念和它们的
实际运行过程。为了提高SVD的精度,我们将会把其应用到推荐系统中去,该推荐系统将会帮助
人们寻找到合适的餐馆。最后,我们讲述一个SVD在图像压缩中的应用例子。

对于上述进行SVD处理会得到两个奇异值。因此就会仿佛有两个概念或主题与此数据集相关联
    我们可以把奇异值想象成一个新空间。与图14-1中的矩阵给出的五维或者七维不同,我们最
终的矩阵只有二维。那么这二维分别是什么呢?创门能告诉我们数据的什么信息?这二维分别对
应图中给出的两个组,右图中已经标示出了其中的一个组。我们可以基于每个组的共同特征来命
名这二维,比如我们得到的美式BBQ和日式食品这二维。
    如何才能将原始数据变换到上述新空间中呢?下一节我们将会进一步详细地介绍SVD,届时
将会了解到SVD是如何得到U和VT两个矩阵的。VT矩阵会将用户映射到BBQ/日式食品空间去。类
似地,u矩阵会将餐馆的菜映射到BBQ/日式食品空间去。真实的数据通常不会像图14-1中的矩阵
那样稠密或整齐.这里如此只是为了便于说明问题。

矩阵分解:

在很多情况下,数据中的一小段携带了数据集中的大部分信息,其他信息则要么是噪声,要
么就是毫不相关的信息。在线性代数中还有很多矩阵分解技术。矩阵分解可以将原始矩阵表示成
新的易于处理的形式,这种新形式是两个或多个矩阵的乘积。我们可以将这种分解过程想象成代
数中的因子分解。如何将12分解成两个数的乘积?(1,12), (2,6)和((3,4)都是合理的答案。
    不同的矩阵分解技术具有不同的性质,其中有些更适合于某个应用,有些则更适合于其他应
用。最常见的一种矩阵分解技术就是SVD。 SVD将原始的数据集矩阵Data分解成三个矩阵U, E
和VT。如果原始矩阵Data是m行n列,那么U, E和VT就分别是m行m列、m行n列和n行n列。

源码如下:

[html] view plain copy print?

  1. <pre name="code" class="html">#coding=utf-8
  2. '''
  3. Created on Mar 8, 2011
  4. @author: Peter
  5. 利用SVD简化数据
  6. 奇异值分解
  7. 优点:简化数据,去除噪声,提高算法的结果。
  8. 缺点:数据的转换可能难以理解。
  9. 适用数据类型:数值型数据。
  10. 总结:
  11. 推荐引擎将物品推荐给用户,协同过滤则是一种基于用户喜好或行为数据的推荐的实现方
  12. 法。协同过滤的核心是相似度计算方法;有很多相似度计算方法都可以用于计算物品或用户之间
  13. 的相似度。通过在低维空间下计算相似度,SVD提高了推荐系引擎的效果。
  14. 在大规模数据集上,SVD的计算和推荐可能是一个很困难的工程问题。通过离线方式来进行
  15. SVD分解和相似度计算,是一种减少冗余计算和推荐所需时间的办法。
  16. 信息检索:
  17. SVD最早的应用是信息检索,我们称利用SVD的方法为隐性语义索引(LSI)或者隐性语义分析(LSA)
  18. LSI中一个矩阵是由文档和词语组成的,当我们在矩阵上应用SVD时,会构建出多个奇异值,这些奇异值代表了文档中
  19. 的概念或主题这一特点可以用于更高效的文档搜索。在词语拼写错误时只基于词语存在与否的简单搜索方法会遇到问题
  20. 简单搜索的另一个问题就是同义词的使用。当查找一个词时,其同义词所在的文档可能并不会匹配上
  21. 推荐系统:
  22. SVD的另一个应用就是推荐系统。简单版本的推荐系统能够计算项或者人之间的相似度,更先进的方法则
  23. 先利用SVD从数据中构建一个主题空间,然后再在该空间下计算其相似度。
  24. >>> from numpy import linalg as la
  25. >>> U,Sigma,VT = la.svd(mat(svdRec.loadExData2()))
  26. >>> Sigma
  27. array([ 15.77075346,  11.40670395,  11.03044558,   4.84639758,
  28. 3.09292055,   2.58097379,   1.00413543,   0.72817072,
  29. 0.43800353,   0.22082113,   0.07367823])
  30. >>> Sig2 = Sigma**2
  31. >>> sum(Sig2)
  32. 541.99999999999955
  33. >>> sum(Sig2)*0.9
  34. 487.79999999999961
  35. >>> sum(Sig2[:2])
  36. 378.8295595113579
  37. >>> Sig3  = mat([[Sigma[0],0,0],[0,Sigma[1],0],[0,0,Sigma[2]]])
  38. >>> U[:,:3]*Sig3*VT[:3,:]
  39. 基于协同过滤的推荐引擎
  40. 相似度的计算
  41. 不利用专家给出的重要属性来描述物品从而计算它们之间的相似度,而是利用用户对他们的意见来计算相似度,这就是协同过滤中所使用的方法
  42. 不关心物品的描述属性,而是严格地按照许多用户的观点来计算相似度
  43. 构建推荐引擎面临的挑战
  44. 我们不必每次估计评分时都做svd分解,对于上述数据集。snd分解在效率上没有太大的区别,
  45. 在更大规模的数据集上,svd分解会降低程序的速度。svd分解可以在程序调入时运行一次。
  46. 在大型系统中,svd每天运行一次或者其运行频率并不高,而且要离线运行
  47. 推荐引擎中还存在其他更多规模扩展性的挑战问题,比如矩阵的表示方法。在系统中存在很多0,
  48. 可以通过只存储非零元素来节省内存和计算开销
  49. 另一个潜在的计算资源浪费来自于相似度得分。在程序中,每次需要一个推荐的分时,都要计算多个物品的相似度得分
  50. 这些得分记录的是物品间的相似度。因此在需要时这些记录可以被另一个用户重复使用。在实际中,另一个普遍的做法就是
  51. 离线计算并保存相似度得分
  52. 推荐引擎面临的另一个问题就是如何在缺乏数据时给出好的推荐,称为冷启动问题,处理起来十分困难。
  53. 该问题的另一种说法是,用户不喜欢一个无效的物品,而用户不喜欢的物品又无效。
  54. 如果推荐只是一个可有可无的功能,那么上述问题不是很大。如果应用的成功与否和推荐的成功与否密切相连,那么问题非常严重
  55. '''
  56. from numpy import *
  57. from numpy import linalg as la
  58. def loadExData():
  59. return[[0, 0, 0, 2, 2],
  60. [0, 0, 0, 3, 3],
  61. [0, 0, 0, 1, 1],
  62. [1, 1, 1, 0, 0],
  63. [2, 2, 2, 0, 0],
  64. [5, 5, 5, 0, 0],
  65. [1, 1, 1, 0, 0]]
  66. def loadExData2():
  67. return[[0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 5],
  68. [0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 3],
  69. [0, 0, 0, 0, 4, 0, 0, 1, 0, 4, 0],
  70. [3, 3, 4, 0, 0, 0, 0, 2, 2, 0, 0],
  71. [5, 4, 5, 0, 0, 0, 0, 5, 5, 0, 0],
  72. [0, 0, 0, 0, 5, 0, 1, 0, 0, 5, 0],
  73. [4, 3, 4, 0, 0, 0, 0, 5, 5, 0, 1],
  74. [0, 0, 0, 4, 0, 4, 0, 0, 0, 0, 4],
  75. [0, 0, 0, 2, 0, 2, 5, 0, 0, 1, 2],
  76. [0, 0, 0, 0, 5, 0, 0, 0, 0, 4, 0],
  77. [1, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0]]
  78. '''
  79. 2范数
  80. 相似度计算
  81. 程序中的3个函数就是上面提到的几种相似度的计算方法。为了便于理解,NumPy的线性代
  82. 数工具箱linalg被作为la导人,函数中假定inA和inB都是列向量。perasSim()函数会检查是否
  83. 存在3个或更多的点。如果不存在,该函数返回1.0,这是因为此时两个向量完全相关。
  84. >>> reload(svdRec)
  85. <module 'svdRec' from 'C:\Users\kernel\Documents\python\ch14\svdRec.py'>
  86. >>> myMat = mat(svdRec.loadExData())
  87. >>> svdRec.ecludSim(myMat[:,0],myMat[:,4])
  88. 0.12973190755680383
  89. >>> svdRec.ecludSim(myMat[:,0],myMat[:,0])
  90. 1.0
  91. >>> svdRec.cosSim(myMat[:,0],myMat[:,4])
  92. 0.5
  93. >>> svdRec.cosSim(myMat[:,0],myMat[:,0])
  94. 1.0
  95. >>> svdRec.pearsSim(myMat[:,0],myMat[:,4])
  96. 0.20596538173840329
  97. >>> svdRec.pearsSim(myMat[:,0],myMat[:,0])
  98. 1.0
  99. '''
  100. def ecludSim(inA,inB):
  101. return 1.0/(1.0 + la.norm(inA - inB))
  102. def pearsSim(inA,inB):
  103. if len(inA) < 3 : return 1.0
  104. return 0.5+0.5*corrcoef(inA, inB, rowvar = 0)[0][1]
  105. def cosSim(inA,inB):
  106. num = float(inA.T*inB)
  107. denom = la.norm(inA)*la.norm(inB)
  108. return 0.5+0.5*(num/denom)
  109. '''
  110. 推荐未尝过的菜肴
  111. 推荐系统的工作过程是:给定一个用户,系统会为此用户返回N个最好的推荐菜。为了实现
  112. 这一点,则需要我们做到:
  113. (1)寻找用户没有评级的菜肴,即在用户-物品矩阵中的0值;
  114. (2)在用户没有评级的所有物品中,对每个物品预计一个可能的评级分数。这就是说,我们
  115. 认为用户可能会对物品的打分(这就是相似度计算的初衷);
  116. (3)对这些物品的评分从高到低进行排序,返回前N个物品。
  117. 上述程序包含了两个函数。第一个函数是standEst(),用来计算在给定相似度计算方法的
  118. 条件下,用户对物品的估计评分值。第二个函数是recommend ( ),也就是推荐引擎.,它会调用
  119. standESt()函数。我们先讨论。tandEst()函数,然后讨论recommend()函数。
  120. 函数s七andEst()的参数包括数据矩阵、用户编号、物品编号和相似度计算方法。假设这里
  121. 的数据矩阵为图14-1和图14-2的形式,即行对应用户、列对应物品。那么,我们首先会得到数据
  122. 集中的物品数目,然后对两个后面用于计算估计评分值的变量进行初始化。接着,我们遍历行中
  123. 的每个物品。如果某个物品评分值为0,就意味着用户没有对该物品评分,跳过了这个物品。该
  124. 循环大体上是对用户评过分的每个物品进行遍历,并将它和其他物品进行比较。变量。verLap
  125. 给出的是两个物品当中已经被评分的那个元素0。如果两者没有任何重合元素,则相似度为。且
  126. 中止本次循环。但是如果存在重合的物品,则基于这些重合物品计算相似度。随后,相似度会不
  127. 断累加,每次计算时还考虑相似度和当前用户评分的乘积。最后,通过除以所有的评分总和,对
  128. 上述相似度评分的乘积进行归一化。这就可以使得最后的评分值在。到5之间,而这些评分值则用
  129. 于对预测值进行排序。
  130. 函数recommend)产生了最高的N个推荐结果。如果不指定N的大小,则默认值为3。该函
  131. 数另外的参数还包括相似度计算方法和估计方法。我们可以使用程序清单14-1中的任意一种相似
  132. 度计算方法。此时我们能采用的估计方法只有一种选择,但是在下一小节中会增加另外一种选择。
  133. 该函数的第一件事就是对给定的用户建立一个未评分的物品列表O。如果不存在未评分物品,那
  134. 么就退出函数;否则,在所有的未评分物品上进行循环。对每个未评分物品,则通过调用
  135. 。七andEst()来产生该物品的预测得分。该物品的编号和估计得分值会放在一个元素列表
  136. i七emScores中。最后按照估计得分,对该列表进行排序并返回O。该列表是从大到小逆序排列
  137. 的,因此其第一个值就是最大值。
  138. 基于物品相似度的推荐引擎
  139. 基于物品的相似度还是基于用户的相似度
  140. 计算两个餐馆菜肴之间的距离,基于物品的相似度
  141. 计算用户距离的方法称作基于用户的相似度
  142. 行与行之间标胶是基于物品的相似度,列与列之间的比较是基于物品的相似度
  143. 基于物品相似度计算会随着物品数量的增加而增加,基于用户的相似度的计算时间
  144. 会随着用户数量的增加而增加。如果用户数目很多,我们可能倾向于使用基于物品相似度的计算方法
  145. 推荐引擎的评价:
  146. 如何对推荐引擎进行评价,此时既没有预测的目标值,也没有用户来调查他们对预测的满意程度
  147. 使用交叉测试的方法,具体做法如下:将某些已知的评分值去掉,然后对他们进行预测,最后计算
  148. 预测值与真实值之间的差异
  149. 推荐引擎评价的指标是称为最小均方根误差的指标,首先计算均方误差的平均值然后取其平方根。如果评级在1~5星范围内
  150. 我们得到的RMSE为1.0,那么意味着我们的预测值和用户给出的真实评价相差了一个星级
  151. 餐馆菜肴推荐引擎
  152. 构建一个基本的推荐引擎,能够找到用户没有尝过额菜肴,然后通过SVD减少特征空间并提高推荐的效果。之后,将程序打包
  153. 并通过可读的人际界面提供给人们使用
  154. '''
  155. #计算在给定相似度计算方法的条件下,用户对物品的估计评分值
  156. def standEst(dataMat, user, simMeas, item):   #数据矩阵,用户编号,物品编号和相似度计算方法
  157. n = shape(dataMat)[1]   #数据集物品数目
  158. simTotal = 0.0; ratSimTotal = 0.0  #对计算估计评分值的变量进行初始化
  159. #如果某个物品的评分值为0,那么意味着用户没有对该物品评分,跳过该物品
  160. #寻找两个用户都评级的物品  对用户评过分的每个物品进行遍历,并将它与其他物品进行比较
  161. for j in range(n):   #对行中每个物品做遍历
  162. userRating = dataMat[user,j]
  163. if userRating == 0: continue
  164. overLap = nonzero(logical_and(dataMat[:,item].A>0, \
  165. dataMat[:,j].A>0))[0]
  166. if len(overLap) == 0: similarity = 0
  167. else: similarity = simMeas(dataMat[overLap,item], \
  168. dataMat[overLap,j])
  169. #如果两者没有任何重合元素,则相似度为0,且终止本次循环  如果存在重合的物品,则基于这些重合物品进行相似度计算
  170. print 'the %d and %d similarity is: %f' % (item, j, similarity)
  171. simTotal += similarity  #对相似度进行累加,每次计算还考虑相似度和当前用户评分的乘积
  172. ratSimTotal += similarity * userRating
  173. if simTotal == 0: return 0
  174. else: return ratSimTotal/simTotal  #除以所有的评分总和,对上述相似度评分的乘积进行归一化。使得最后的评分值在0~5之间,这些评分值则用于对预测值进行排序
  175. '''
  176. 基于SVD的评分估计
  177. 上述程序中包含有一个函数svdEst()。在recommend)中,这个函数用于替换对。tand-
  178. Est()的调用,该函数对给定用户给定物品构建了一个评分估计值。如果将该函数与程序清单
  179. 14-2中的standEst()函数进行比较,就会发现很多行代码都很相似。该函数的不同之处就在于
  180. 它在第3行对数据集进行了SVD分解。在SVD分解之后,我们只利用包含了90%能量值的奇异值,
  181. 这些奇异值会以NumPy}C组的形式得以保存。因此如果要进行矩阵运算,那么就必须要用这些奇
  182. 异值构建出一个对角矩阵.。然后,利用u矩阵将物品转换到低维空间中)o
  183. 对于给定的用户,for循环在用户对应行的所有元素上进行遍历。这和。tandEst()函数中
  184. 的for循环的目的一样,只不过这里的相似度计算是在低维空间下进行的。相似度的计算方法也
  185. 会作为一个参数传递给该函数。然后,我们对相似度求和,同时对相似度及对应评分值的乘积求
  186. >>> import svdRec
  187. >>> myMat = mat(svdRec.loadExData())
  188. >>> myMat[0,1] = myMat[0,0] = myMat[1,0] = myMat[2,0] = 4
  189. >>> myMat[3,3] = 2
  190. >>> myMat
  191. matrix([[4, 4, 0, 2, 2],
  192. [4, 0, 0, 3, 3],
  193. [4, 0, 0, 1, 1],
  194. [1, 1, 1, 2, 0],
  195. [2, 2, 2, 0, 0],
  196. [5, 5, 5, 0, 0],
  197. [1, 1, 1, 0, 0]])
  198. >>> svdRec.recommend(myMat,2)
  199. the 1 and 0 similarity is: 1.000000
  200. the 1 and 3 similarity is: 0.928746
  201. the 1 and 4 similarity is: 1.000000
  202. the 2 and 0 similarity is: 1.000000
  203. the 2 and 3 similarity is: 1.000000
  204. the 2 and 4 similarity is: 0.000000
  205. [(2, 2.5), (1, 2.0243290220056256)]
  206. >>> svdRec.recommend(myMat,2,simMeas = svdRec.ecludSim)
  207. the 1 and 0 similarity is: 1.000000
  208. the 1 and 3 similarity is: 0.309017
  209. the 1 and 4 similarity is: 0.333333
  210. the 2 and 0 similarity is: 1.000000
  211. the 2 and 3 similarity is: 0.500000
  212. the 2 and 4 similarity is: 0.000000
  213. [(2, 3.0), (1, 2.8266504712098603)]
  214. >>> svdRec.recommend(myMat,2,simMeas = svdRec.pearsSim)
  215. the 1 and 0 similarity is: 1.000000
  216. the 1 and 3 similarity is: 1.000000
  217. the 1 and 4 similarity is: 1.000000
  218. the 2 and 0 similarity is: 1.000000
  219. the 2 and 3 similarity is: 1.000000
  220. the 2 and 4 similarity is: 0.000000
  221. [(2, 2.5), (1, 2.0)]
  222. '''
  223. def svdEst(dataMat, user, simMeas, item):
  224. n = shape(dataMat)[1]
  225. simTotal = 0.0; ratSimTotal = 0.0
  226. U,Sigma,VT = la.svd(dataMat)  #进行svd分解  分解之后只利用包含了90%能量值的奇异值,这些奇异值以numpy数组的形式得以保存
  227. Sig4 = mat(eye(4)*Sigma[:4]) #arrange Sig4 into a diagonal matrix  用奇异值 建立对角矩阵
  228. xformedItems = dataMat.T * U[:,:4] * Sig4.I  #create transformed items  用U矩阵将物品转换成低维空间  构建转换后的物品
  229. for j in range(n):  #for循环相似度计算是在低维空间下进行的  相似度的计算作为一个参数传递给该函数
  230. userRating = dataMat[user,j]
  231. if userRating == 0 or j==item: continue
  232. similarity = simMeas(xformedItems[item,:].T,\
  233. xformedItems[j,:].T)
  234. print 'the %d and %d similarity is: %f' % (item, j, similarity)
  235. simTotal += similarity   #对相似度求和,同时对相似度及对应评分值的乘积求和
  236. ratSimTotal += similarity * userRating
  237. if simTotal == 0: return 0
  238. else: return ratSimTotal/simTotal
  239. #推荐引擎,调用standEst函数  函数recommend产生了最高的n个推荐结果,如果不指定N的大小,则默认值为3  参数还包括相似度计算方法和估计方法
  240. def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):
  241. unratedItems = nonzero(dataMat[user,:].A==0)[1]#find unrated items 建立一个未评分的物品列表
  242. if len(unratedItems) == 0: return 'you rated everything'   #寻找未评级的物品 如果不存在未评分的物品,那么退出函数  否则在未评分的物品上进行循环
  243. itemScores = []
  244. for item in unratedItems:
  245. estimatedScore = estMethod(dataMat, user, simMeas, item)  #对每个未评分的物品,通过调用standEst产生该物品的预测得分,该物品的编号和估计得分值放在一个元素列表itemscores中
  246. itemScores.append((item, estimatedScore))
  247. return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[:N]    #寻找前n个未评级的物品  按照估计得分,对该列表进行排序并返回,该列表从大到小逆序排序,第一个值就是最大值
  248. '''
  249. 基于SVD的图像压缩
  250. 上述程序中第一个函数printMat()的作用是打印矩阵。由于矩阵包含了浮点数,因此必须
  251. 定义浅色和深色。这里通过一个阑值来界定,后面也可以调节该值。该函数遍历所有的矩阵元素,
  252. 当元素大于阑值时打印1,否则打印。。
  253. '''
  254. def printMat(inMat, thresh=0.8):   #打印矩阵,矩阵包含了浮点数,因此必须定义浅色和深色 thresh做阈值界定,遍历所有的矩阵元素,当元素大于阈值时打印1,反之打印0
  255. for i in range(32):
  256. for k in range(32):
  257. if float(inMat[i,k]) > thresh:
  258. print 1,
  259. else: print 0,
  260. print ''
  261. '''
  262. 实验图像的压缩  允许基于任意给定的奇异值 数目来重构图像,该函数构建了一个列表,然后打开文本文件,从文件中以数值方式读入字符
  263. 在矩阵调入之后,就可以在屏幕上输出该矩阵了。接下来就开始对原始图像进行SVD分解并重构图像。在程序中,
  264. 通过将sigma重新否成sigrecon来实现这一点,digma是一个对角矩阵。因此需要建立一个全0矩阵
  265. 然后将前面的那些奇异值填充到对角线上。最后,通过阶段的U和V^2矩阵,用sigrecon得到重构后的矩阵,该矩阵通过printmat函数输出
  266. '''
  267. def imgCompress(numSV=3, thresh=0.8):
  268. myl = []
  269. for line in open('0_5.txt').readlines():
  270. newRow = []
  271. for i in range(32):
  272. newRow.append(int(line[i]))
  273. myl.append(newRow)
  274. myMat = mat(myl)
  275. print "****original matrix******"
  276. printMat(myMat, thresh)
  277. U,Sigma,VT = la.svd(myMat)
  278. SigRecon = mat(zeros((numSV, numSV)))
  279. for k in range(numSV):#construct diagonal matrix from vector
  280. SigRecon[k,k] = Sigma[k]
  281. reconMat = U[:,:numSV]*SigRecon*VT[:numSV,:]
  282. print "****reconstructed matrix using %d singular values******" % numSV
  283. printMat(reconMat, thresh)

<pre name="code" class="html">#coding=utf-8
'''
Created on Mar 8, 2011@author: Peter
利用SVD简化数据奇异值分解
优点:简化数据,去除噪声,提高算法的结果。
缺点:数据的转换可能难以理解。
适用数据类型:数值型数据。总结:
推荐引擎将物品推荐给用户,协同过滤则是一种基于用户喜好或行为数据的推荐的实现方
法。协同过滤的核心是相似度计算方法;有很多相似度计算方法都可以用于计算物品或用户之间
的相似度。通过在低维空间下计算相似度,SVD提高了推荐系引擎的效果。在大规模数据集上,SVD的计算和推荐可能是一个很困难的工程问题。通过离线方式来进行
SVD分解和相似度计算,是一种减少冗余计算和推荐所需时间的办法。信息检索:
SVD最早的应用是信息检索,我们称利用SVD的方法为隐性语义索引(LSI)或者隐性语义分析(LSA)
LSI中一个矩阵是由文档和词语组成的,当我们在矩阵上应用SVD时,会构建出多个奇异值,这些奇异值代表了文档中
的概念或主题这一特点可以用于更高效的文档搜索。在词语拼写错误时只基于词语存在与否的简单搜索方法会遇到问题
简单搜索的另一个问题就是同义词的使用。当查找一个词时,其同义词所在的文档可能并不会匹配上推荐系统:
SVD的另一个应用就是推荐系统。简单版本的推荐系统能够计算项或者人之间的相似度,更先进的方法则
先利用SVD从数据中构建一个主题空间,然后再在该空间下计算其相似度。>>> from numpy import linalg as la
>>> U,Sigma,VT = la.svd(mat(svdRec.loadExData2()))
>>> Sigma
array([ 15.77075346,  11.40670395,  11.03044558,   4.84639758,3.09292055,   2.58097379,   1.00413543,   0.72817072,0.43800353,   0.22082113,   0.07367823])
>>> Sig2 = Sigma**2
>>> sum(Sig2)
541.99999999999955
>>> sum(Sig2)*0.9
487.79999999999961
>>> sum(Sig2[:2])
378.8295595113579
>>> Sig3  = mat([[Sigma[0],0,0],[0,Sigma[1],0],[0,0,Sigma[2]]])
>>> U[:,:3]*Sig3*VT[:3,:]基于协同过滤的推荐引擎相似度的计算
不利用专家给出的重要属性来描述物品从而计算它们之间的相似度,而是利用用户对他们的意见来计算相似度,这就是协同过滤中所使用的方法
不关心物品的描述属性,而是严格地按照许多用户的观点来计算相似度构建推荐引擎面临的挑战
我们不必每次估计评分时都做svd分解,对于上述数据集。snd分解在效率上没有太大的区别,
在更大规模的数据集上,svd分解会降低程序的速度。svd分解可以在程序调入时运行一次。
在大型系统中,svd每天运行一次或者其运行频率并不高,而且要离线运行推荐引擎中还存在其他更多规模扩展性的挑战问题,比如矩阵的表示方法。在系统中存在很多0,
可以通过只存储非零元素来节省内存和计算开销
另一个潜在的计算资源浪费来自于相似度得分。在程序中,每次需要一个推荐的分时,都要计算多个物品的相似度得分
这些得分记录的是物品间的相似度。因此在需要时这些记录可以被另一个用户重复使用。在实际中,另一个普遍的做法就是
离线计算并保存相似度得分推荐引擎面临的另一个问题就是如何在缺乏数据时给出好的推荐,称为冷启动问题,处理起来十分困难。
该问题的另一种说法是,用户不喜欢一个无效的物品,而用户不喜欢的物品又无效。
如果推荐只是一个可有可无的功能,那么上述问题不是很大。如果应用的成功与否和推荐的成功与否密切相连,那么问题非常严重
'''
from numpy import *
from numpy import linalg as ladef loadExData():return[[0, 0, 0, 2, 2],[0, 0, 0, 3, 3],[0, 0, 0, 1, 1],[1, 1, 1, 0, 0],[2, 2, 2, 0, 0],[5, 5, 5, 0, 0],[1, 1, 1, 0, 0]]def loadExData2():return[[0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 5],[0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 3],[0, 0, 0, 0, 4, 0, 0, 1, 0, 4, 0],[3, 3, 4, 0, 0, 0, 0, 2, 2, 0, 0],[5, 4, 5, 0, 0, 0, 0, 5, 5, 0, 0],[0, 0, 0, 0, 5, 0, 1, 0, 0, 5, 0],[4, 3, 4, 0, 0, 0, 0, 5, 5, 0, 1],[0, 0, 0, 4, 0, 4, 0, 0, 0, 0, 4],[0, 0, 0, 2, 0, 2, 5, 0, 0, 1, 2],[0, 0, 0, 0, 5, 0, 0, 0, 0, 4, 0],[1, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0]]
'''
2范数
相似度计算程序中的3个函数就是上面提到的几种相似度的计算方法。为了便于理解,NumPy的线性代
数工具箱linalg被作为la导人,函数中假定inA和inB都是列向量。perasSim()函数会检查是否
存在3个或更多的点。如果不存在,该函数返回1.0,这是因为此时两个向量完全相关。>>> reload(svdRec)
<module 'svdRec' from 'C:\Users\kernel\Documents\python\ch14\svdRec.py'>
>>> myMat = mat(svdRec.loadExData())
>>> svdRec.ecludSim(myMat[:,0],myMat[:,4])
0.12973190755680383
>>> svdRec.ecludSim(myMat[:,0],myMat[:,0])
1.0
>>> svdRec.cosSim(myMat[:,0],myMat[:,4])
0.5
>>> svdRec.cosSim(myMat[:,0],myMat[:,0])
1.0
>>> svdRec.pearsSim(myMat[:,0],myMat[:,4])
0.20596538173840329
>>> svdRec.pearsSim(myMat[:,0],myMat[:,0])
1.0'''
def ecludSim(inA,inB):return 1.0/(1.0 + la.norm(inA - inB))def pearsSim(inA,inB):if len(inA) < 3 : return 1.0return 0.5+0.5*corrcoef(inA, inB, rowvar = 0)[0][1]def cosSim(inA,inB):num = float(inA.T*inB)denom = la.norm(inA)*la.norm(inB)return 0.5+0.5*(num/denom)
'''
推荐未尝过的菜肴推荐系统的工作过程是:给定一个用户,系统会为此用户返回N个最好的推荐菜。为了实现
这一点,则需要我们做到:(1)寻找用户没有评级的菜肴,即在用户-物品矩阵中的0值;(2)在用户没有评级的所有物品中,对每个物品预计一个可能的评级分数。这就是说,我们
认为用户可能会对物品的打分(这就是相似度计算的初衷);(3)对这些物品的评分从高到低进行排序,返回前N个物品。上述程序包含了两个函数。第一个函数是standEst(),用来计算在给定相似度计算方法的
条件下,用户对物品的估计评分值。第二个函数是recommend ( ),也就是推荐引擎.,它会调用
standESt()函数。我们先讨论。tandEst()函数,然后讨论recommend()函数。函数s七andEst()的参数包括数据矩阵、用户编号、物品编号和相似度计算方法。假设这里
的数据矩阵为图14-1和图14-2的形式,即行对应用户、列对应物品。那么,我们首先会得到数据
集中的物品数目,然后对两个后面用于计算估计评分值的变量进行初始化。接着,我们遍历行中
的每个物品。如果某个物品评分值为0,就意味着用户没有对该物品评分,跳过了这个物品。该
循环大体上是对用户评过分的每个物品进行遍历,并将它和其他物品进行比较。变量。verLap给出的是两个物品当中已经被评分的那个元素0。如果两者没有任何重合元素,则相似度为。且
中止本次循环。但是如果存在重合的物品,则基于这些重合物品计算相似度。随后,相似度会不
断累加,每次计算时还考虑相似度和当前用户评分的乘积。最后,通过除以所有的评分总和,对
上述相似度评分的乘积进行归一化。这就可以使得最后的评分值在。到5之间,而这些评分值则用
于对预测值进行排序。函数recommend)产生了最高的N个推荐结果。如果不指定N的大小,则默认值为3。该函
数另外的参数还包括相似度计算方法和估计方法。我们可以使用程序清单14-1中的任意一种相似
度计算方法。此时我们能采用的估计方法只有一种选择,但是在下一小节中会增加另外一种选择。
该函数的第一件事就是对给定的用户建立一个未评分的物品列表O。如果不存在未评分物品,那
么就退出函数;否则,在所有的未评分物品上进行循环。对每个未评分物品,则通过调用
。七andEst()来产生该物品的预测得分。该物品的编号和估计得分值会放在一个元素列表
i七emScores中。最后按照估计得分,对该列表进行排序并返回O。该列表是从大到小逆序排列
的,因此其第一个值就是最大值。基于物品相似度的推荐引擎
基于物品的相似度还是基于用户的相似度
计算两个餐馆菜肴之间的距离,基于物品的相似度
计算用户距离的方法称作基于用户的相似度
行与行之间标胶是基于物品的相似度,列与列之间的比较是基于物品的相似度
基于物品相似度计算会随着物品数量的增加而增加,基于用户的相似度的计算时间
会随着用户数量的增加而增加。如果用户数目很多,我们可能倾向于使用基于物品相似度的计算方法推荐引擎的评价:
如何对推荐引擎进行评价,此时既没有预测的目标值,也没有用户来调查他们对预测的满意程度
使用交叉测试的方法,具体做法如下:将某些已知的评分值去掉,然后对他们进行预测,最后计算
预测值与真实值之间的差异推荐引擎评价的指标是称为最小均方根误差的指标,首先计算均方误差的平均值然后取其平方根。如果评级在1~5星范围内
我们得到的RMSE为1.0,那么意味着我们的预测值和用户给出的真实评价相差了一个星级餐馆菜肴推荐引擎
构建一个基本的推荐引擎,能够找到用户没有尝过额菜肴,然后通过SVD减少特征空间并提高推荐的效果。之后,将程序打包
并通过可读的人际界面提供给人们使用'''
#计算在给定相似度计算方法的条件下,用户对物品的估计评分值
def standEst(dataMat, user, simMeas, item):   #数据矩阵,用户编号,物品编号和相似度计算方法n = shape(dataMat)[1]   #数据集物品数目simTotal = 0.0; ratSimTotal = 0.0  #对计算估计评分值的变量进行初始化
#如果某个物品的评分值为0,那么意味着用户没有对该物品评分,跳过该物品
#寻找两个用户都评级的物品  对用户评过分的每个物品进行遍历,并将它与其他物品进行比较for j in range(n):   #对行中每个物品做遍历userRating = dataMat[user,j]if userRating == 0: continueoverLap = nonzero(logical_and(dataMat[:,item].A>0, \dataMat[:,j].A>0))[0]if len(overLap) == 0: similarity = 0  else: similarity = simMeas(dataMat[overLap,item], \dataMat[overLap,j])#如果两者没有任何重合元素,则相似度为0,且终止本次循环  如果存在重合的物品,则基于这些重合物品进行相似度计算print 'the %d and %d similarity is: %f' % (item, j, similarity)simTotal += similarity  #对相似度进行累加,每次计算还考虑相似度和当前用户评分的乘积ratSimTotal += similarity * userRatingif simTotal == 0: return 0else: return ratSimTotal/simTotal  #除以所有的评分总和,对上述相似度评分的乘积进行归一化。使得最后的评分值在0~5之间,这些评分值则用于对预测值进行排序
'''
基于SVD的评分估计上述程序中包含有一个函数svdEst()。在recommend)中,这个函数用于替换对。tand-
Est()的调用,该函数对给定用户给定物品构建了一个评分估计值。如果将该函数与程序清单
14-2中的standEst()函数进行比较,就会发现很多行代码都很相似。该函数的不同之处就在于
它在第3行对数据集进行了SVD分解。在SVD分解之后,我们只利用包含了90%能量值的奇异值,
这些奇异值会以NumPy}C组的形式得以保存。因此如果要进行矩阵运算,那么就必须要用这些奇
异值构建出一个对角矩阵.。然后,利用u矩阵将物品转换到低维空间中)o对于给定的用户,for循环在用户对应行的所有元素上进行遍历。这和。tandEst()函数中
的for循环的目的一样,只不过这里的相似度计算是在低维空间下进行的。相似度的计算方法也
会作为一个参数传递给该函数。然后,我们对相似度求和,同时对相似度及对应评分值的乘积求>>> import svdRec
>>> myMat = mat(svdRec.loadExData())
>>> myMat[0,1] = myMat[0,0] = myMat[1,0] = myMat[2,0] = 4
>>> myMat[3,3] = 2
>>> myMat
matrix([[4, 4, 0, 2, 2],[4, 0, 0, 3, 3],[4, 0, 0, 1, 1],[1, 1, 1, 2, 0],[2, 2, 2, 0, 0],[5, 5, 5, 0, 0],[1, 1, 1, 0, 0]])
>>> svdRec.recommend(myMat,2)
the 1 and 0 similarity is: 1.000000
the 1 and 3 similarity is: 0.928746
the 1 and 4 similarity is: 1.000000
the 2 and 0 similarity is: 1.000000
the 2 and 3 similarity is: 1.000000
the 2 and 4 similarity is: 0.000000
[(2, 2.5), (1, 2.0243290220056256)]>>> svdRec.recommend(myMat,2,simMeas = svdRec.ecludSim)
the 1 and 0 similarity is: 1.000000
the 1 and 3 similarity is: 0.309017
the 1 and 4 similarity is: 0.333333
the 2 and 0 similarity is: 1.000000
the 2 and 3 similarity is: 0.500000
the 2 and 4 similarity is: 0.000000
[(2, 3.0), (1, 2.8266504712098603)]
>>> svdRec.recommend(myMat,2,simMeas = svdRec.pearsSim)
the 1 and 0 similarity is: 1.000000
the 1 and 3 similarity is: 1.000000
the 1 and 4 similarity is: 1.000000
the 2 and 0 similarity is: 1.000000
the 2 and 3 similarity is: 1.000000
the 2 and 4 similarity is: 0.000000
[(2, 2.5), (1, 2.0)]
'''
def svdEst(dataMat, user, simMeas, item):n = shape(dataMat)[1]simTotal = 0.0; ratSimTotal = 0.0U,Sigma,VT = la.svd(dataMat)  #进行svd分解  分解之后只利用包含了90%能量值的奇异值,这些奇异值以numpy数组的形式得以保存Sig4 = mat(eye(4)*Sigma[:4]) #arrange Sig4 into a diagonal matrix  用奇异值 建立对角矩阵xformedItems = dataMat.T * U[:,:4] * Sig4.I  #create transformed items  用U矩阵将物品转换成低维空间  构建转换后的物品for j in range(n):  #for循环相似度计算是在低维空间下进行的  相似度的计算作为一个参数传递给该函数userRating = dataMat[user,j]if userRating == 0 or j==item: continuesimilarity = simMeas(xformedItems[item,:].T,\xformedItems[j,:].T)print 'the %d and %d similarity is: %f' % (item, j, similarity)simTotal += similarity   #对相似度求和,同时对相似度及对应评分值的乘积求和ratSimTotal += similarity * userRatingif simTotal == 0: return 0else: return ratSimTotal/simTotal
#推荐引擎,调用standEst函数  函数recommend产生了最高的n个推荐结果,如果不指定N的大小,则默认值为3  参数还包括相似度计算方法和估计方法
def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):unratedItems = nonzero(dataMat[user,:].A==0)[1]#find unrated items 建立一个未评分的物品列表if len(unratedItems) == 0: return 'you rated everything'   #寻找未评级的物品 如果不存在未评分的物品,那么退出函数  否则在未评分的物品上进行循环itemScores = []for item in unratedItems:estimatedScore = estMethod(dataMat, user, simMeas, item)  #对每个未评分的物品,通过调用standEst产生该物品的预测得分,该物品的编号和估计得分值放在一个元素列表itemscores中itemScores.append((item, estimatedScore))return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[:N]    #寻找前n个未评级的物品  按照估计得分,对该列表进行排序并返回,该列表从大到小逆序排序,第一个值就是最大值
'''
基于SVD的图像压缩上述程序中第一个函数printMat()的作用是打印矩阵。由于矩阵包含了浮点数,因此必须
定义浅色和深色。这里通过一个阑值来界定,后面也可以调节该值。该函数遍历所有的矩阵元素,
当元素大于阑值时打印1,否则打印。。
'''
def printMat(inMat, thresh=0.8):   #打印矩阵,矩阵包含了浮点数,因此必须定义浅色和深色 thresh做阈值界定,遍历所有的矩阵元素,当元素大于阈值时打印1,反之打印0 for i in range(32):for k in range(32):if float(inMat[i,k]) > thresh:print 1,else: print 0,print '''''
实验图像的压缩  允许基于任意给定的奇异值 数目来重构图像,该函数构建了一个列表,然后打开文本文件,从文件中以数值方式读入字符
在矩阵调入之后,就可以在屏幕上输出该矩阵了。接下来就开始对原始图像进行SVD分解并重构图像。在程序中,
通过将sigma重新否成sigrecon来实现这一点,digma是一个对角矩阵。因此需要建立一个全0矩阵
然后将前面的那些奇异值填充到对角线上。最后,通过阶段的U和V^2矩阵,用sigrecon得到重构后的矩阵,该矩阵通过printmat函数输出
'''
def imgCompress(numSV=3, thresh=0.8):myl = []for line in open('0_5.txt').readlines():newRow = []for i in range(32):newRow.append(int(line[i]))myl.append(newRow)myMat = mat(myl)print "****original matrix******"printMat(myMat, thresh)U,Sigma,VT = la.svd(myMat)SigRecon = mat(zeros((numSV, numSV)))for k in range(numSV):#construct diagonal matrix from vectorSigRecon[k,k] = Sigma[k]reconMat = U[:,:numSV]*SigRecon*VT[:numSV,:]print "****reconstructed matrix using %d singular values******" % numSVprintMat(reconMat, thresh)

推荐引擎将物品推荐给用户,协同过滤则是一种基于用户喜好或行为数据的推荐的实现方
法。协同过滤的核心是相似度计算方法;有很多相似度计算方法都可以用于计算物品或用户之间
的相似度。通过在低维空间下计算相似度,SVD提高了推荐系引擎的效果。
    在大规模数据集上,SVD的计算和推荐可能是一个很困难的工程问题。通过离线方式来进行
SVD分解和相似度计算,是一种减少冗余计算和推荐所需时间的办法。

SVDchapter14 机器学习之利用SVD简化数据相关推荐

  1. chapter14 机器学习之利用SVD简化数据

    餐馆可划分为很多类别,比如美式.中式.日式.牛排馆.素食店,等等.你是否想过这些 类别够用吗?或许人们喜欢这些的混合类别,或者类似中式素食店那样的子类别.如何才能知道 到底有多少类餐馆呢?我们也许可以 ...

  2. 【机器学习实战】第14章 利用SVD简化数据

    第14章 利用SVD简化数据 SVD 概述 奇异值分解(SVD, Singular Value Decomposition):提取信息的一种方法,可以把 SVD 看成是从噪声数据中抽取相关特征.从生物 ...

  3. 机器学习实战(十四)利用SVD简化数据

    第十四章 利用SVD简化数据 14.1 SVD的应用 14.1.1 隐形语义索引 14.1.2 推荐系统 14.2 矩阵分解(SVD矩阵分解) 14.3 利用python实现SVD 14.4 基于协同 ...

  4. chapter13 机器学习之利用PCA简化数据

    LDA: LDA的全称是Linear Discriminant Analysis(线性判别分析),是一种supervised learning.有些资料上也称为是Fisher's Linear Dis ...

  5. 教你学Python38-利用SVD简化数据

    SVD 概述 奇异值分解(SVD, Singular Value Decomposition):提取信息的一种方法,可以把 SVD 看成是从噪声数据中抽取相关特征.从生物信息学到金融学,SVD 是提取 ...

  6. 机器学习-推荐系统-利用用户标签数据

    在之前的博文中介绍了三种方法给用户推荐物品. 1)UserCF:给用户推荐和他们兴趣爱好相似的其他用户喜欢的物品. 2) ItemCF:给用户推荐与他喜欢过的物品相似的物品. 3) LFM:通过一些特 ...

  7. 利用奇异值分解(SVD)简化数据

    特征值与特征向量 下面这部分内容摘自:强大的矩阵奇异值分解(SVD)及其应用 特征值分解和奇异值分解在机器学习领域都是属于满地可见的方法.两者有着很紧密的关系,在接下来会谈到,特征值分解和奇异值分解的 ...

  8. 机器学习实战(十一)利用PCA来简化数据

    第十三章 利用PCA来简化数据 13.1 降维技术 13.1.1 主成分分析(PrincipalComponentAnalysis,PCA) 13.1.2 因子分析(Factor Analysis) ...

  9. 《机器学习实战》之十三——利用PCA来简化数据

    PCA目录 一.前言 二.降维技术 三.PCA 1.PCA的数学原理 (1)向量内积与投影 (2)基 (3)基变换 (4)方差与协方差 2.PCA算法步骤 3.在numpy中实现PCA (1)零均值化 ...

最新文章

  1. 这一次,我拒绝了Python,选择了Go
  2. 27岁华裔小伙一战成名!搞出美国新冠最准预测模型,一人干翻专业机构,彭博:Superstar...
  3. 十种排序算法的java汇总
  4. 用BenchmarkDotNet看Property
  5. 大量删除MySQL中的数据
  6. 开源及第三方软件管理体系
  7. a标签去掉下划线_怎么去掉html a超链接下划线
  8. HTML+CSS+JS——仿京东(7页) 大学生简单个人静态HTML网页设计作品 DIV布局个人介绍网页模板代码 DW学生个人网站制作成品下载
  9. DOORS和Reqtify — 需求管理和需求追溯工具
  10. linux 显卡 1050ti,MAX-Q终于出中端卡了 GTX1050Ti MAX-Q显卡曝光
  11. 多页面实现-个人中心
  12. Extremely hard RSA 低加密指数攻击
  13. Go--Redis快速入门指南
  14. 持续集成(第二版) Martin Fowler著
  15. 三维扫描在建筑行业应用综述
  16. 从英雄无极看中国电影的弊端与不确定未来
  17. 真题集P110---2018年真题
  18. java 7 升级后,控制面板里找不到java图标了
  19. 【博客420】arp代理与arp代答
  20. 爱云兔app v2.0.1

热门文章

  1. [leetcode]求数组的第k个最大值,python快排解法
  2. sql out apply_在SQL Server中CROSS APPLY和OUTER APPLY之间的区别
  3. 在SQL Server中配置索引创建内存设置的最佳实践
  4. BigInteger详解
  5. LINUX mysql 源码安装
  6. C++设计模式-Mediator中介者模式
  7. windows api学习笔记-键盘钩子
  8. 北京科技大学计算机专业博导,北京科技大学计算机与通信工程学院-班晓娟
  9. 个人项目总结----By Li Zhang
  10. 文件校验和(checksum或Hash)计算工具