基本信息

  1. from numpy import *
  2. from numpy import linalg as la

SVD能够对矩阵做到降维简化的效果

  1. U,Sigma,VT = la.svd(dataMat)

分解之后可以得到三个矩阵
第二个是一个对角矩阵(在numpy里为了节约空间就直接是一个数组)。可以通过其他办法重新复原为一个对角

  1. Sig4 = mat(eye(4)*Sigma[:4])
  2. #或者
  3. SigRecon = mat(zeros((numSV, numSV)))
  4. for k in range(numSV):#construct diagonal matrix from vector
  5. SigRecon[k,k] = Sigma[k]

这个对角矩阵决定了信息的量
比如说想要保留90%的信息,可以选择[0:m]的sigma使得平方和是总的90%
或者是通过观察等等
则原先为n的sigma就削减为m

原先的是U[m,n]Sigma[m,n]VT[n,n]=Data[m,n]
这个时候化简为U[m,x]Sigma[x,x]VT[x,n]=Data[m,n]
于是就起到了简化数据和减噪的功能

例子

推荐系统

推荐系统就是基于一些数据向量推荐相似的产品
在书中的例子就是多个用户对多个产品进行了打分(每个用户不一定对所有的产品打分,推荐的目标就是推荐打分最高的产品,其中需要对没有打分的产品进行推理)

这里的应用就是在推理得分上
对推荐的时候找到这个用户的某个未打分产品,遍历已打分的产品,对任意的已打分产品搜集得到其他用户(同时打分了这个已打分产品和未打分产品)对这个的打分情况,假设为向量X(维数未知),同时未打分产品也有一个打分向量,计算两个向量的相似度。把此用户对这个已打分产品的打分乘上相似度后累加。

基本原理就是相似的产品,大家的打分情况相似,那么此用户对这个产品的打分可以推理到未打分产品上
若两产品的打分情况相似(其他人给出了相似的分数),则打分可以较大幅度的借鉴,反之则较小

相似度计算

  1. def ecludSim(inA,inB):
  2. return 1.0/(1.0 + la.norm(inA - inB))
  3. def pearsSim(inA,inB):
  4. if len(inA) < 3 : return 1.0
  5. return 0.5+0.5*corrcoef(inA, inB, rowvar = 0)[0][1]
  6. def cosSim(inA,inB):
  7. num = float(inA.T*inB)
  8. denom = la.norm(inA)*la.norm(inB)
  9. return 0.5+0.5*(num/denom)

SVD应用

对于一数据集MN,M为用户数,N为对应打分
使用矩阵分解保留维数X的sigma
DataT[N,M]
U[M,X]Sigma[X,X]
操作之后得到N
X维度的矩阵用以推理打分(可以近似的看作神经网络里加上了全连接层,原先N个向量(M长度)经过全链接层得到N个长度为X的向量),然后向量之间做所谓的相似度用以推理分数。

  1. def standEst(dataMat, user, simMeas, item):
  2. n = shape(dataMat)[1]
  3. simTotal = 0.0; ratSimTotal = 0.0
  4. for j in range(n):
  5. userRating = dataMat[user,j]
  6. if userRating == 0: continue
  7. overLap = nonzero(logical_and(dataMat[:,item].A>0, \
  8. dataMat[:,j].A>0))[0]
  9. if len(overLap) == 0: similarity = 0
  10. else: similarity = simMeas(dataMat[overLap,item], \
  11. dataMat[overLap,j])
  12. print ('the %d and %d similarity is: %f' % (item, j, similarity))
  13. simTotal += similarity
  14. ratSimTotal += similarity * userRating
  15. if simTotal == 0: return 0
  16. else: return ratSimTotal/simTotal
  17. def svdEst(dataMat, user, simMeas, item):
  18. n = shape(dataMat)[1]
  19. simTotal = 0.0; ratSimTotal = 0.0
  20. U,Sigma,VT = la.svd(dataMat)
  21. #print(Sigma)
  22. Sig4 = mat(eye(4)*Sigma[:4]) #arrange Sig4 into a diagonal matrix
  23. #print(Sig4)
  24. xformedItems = dataMat.T * U[:,:4] * Sig4.I #create transformed items
  25. print(dataMat.shape)
  26. print(xformedItems.shape)
  27. for j in range(n):
  28. userRating = dataMat[user,j]
  29. if userRating == 0 or j==item: continue
  30. print(xformedItems[item,:].shape)
  31. similarity = simMeas(xformedItems[item,:].T,\
  32. xformedItems[j,:].T)
  33. print ('the %d and %d similarity is: %f' % (item, j, similarity))
  34. simTotal += similarity
  35. ratSimTotal += similarity * userRating
  36. if simTotal == 0: return 0
  37. else: return ratSimTotal/simTotal

图片压缩

和上述的同理,对Sigma进行裁剪,得到了更小的三个矩阵,拼接最后的结果却能够较好的还原原矩阵

  1. def imgCompress(numSV=3, thresh=0.8):
  2. myl = []
  3. for line in open('0_5.txt').readlines():
  4. newRow = []
  5. for i in range(32):
  6. newRow.append(int(line[i]))
  7. myl.append(newRow)
  8. myMat = mat(myl)
  9. print ("****original matrix******")
  10. printMat(myMat, thresh)
  11. U,Sigma,VT = la.svd(myMat)
  12. SigRecon = mat(zeros((numSV, numSV)))
  13. for k in range(numSV):#construct diagonal matrix from vector
  14. SigRecon[k,k] = Sigma[k]
  15. reconMat = U[:,:numSV]*SigRecon*VT[:numSV,:]
  16. print ("****reconstructed matrix using %d singular values******" % numSV)
  17. printMat(reconMat, thresh)