基本信息
from numpy import *
from numpy import linalg as la
SVD能够对矩阵做到降维简化的效果
U,Sigma,VT = la.svd(dataMat)
分解之后可以得到三个矩阵
第二个是一个对角矩阵(在numpy里为了节约空间就直接是一个数组)。可以通过其他办法重新复原为一个对角
Sig4 = mat(eye(4)*Sigma[:4])
#或者
SigRecon = mat(zeros((numSV, numSV)))
for k in range(numSV):#construct diagonal matrix from vector
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(维数未知),同时未打分产品也有一个打分向量,计算两个向量的相似度。把此用户对这个已打分产品的打分乘上相似度后累加。
基本原理就是相似的产品,大家的打分情况相似,那么此用户对这个产品的打分可以推理到未打分产品上
若两产品的打分情况相似(其他人给出了相似的分数),则打分可以较大幅度的借鉴,反之则较小
相似度计算
def ecludSim(inA,inB):
return 1.0/(1.0 + la.norm(inA - inB))
def pearsSim(inA,inB):
if len(inA) < 3 : return 1.0
return 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)
SVD应用
对于一数据集MN,M为用户数,N为对应打分
使用矩阵分解保留维数X的sigma
DataT[N,M]U[M,X]Sigma[X,X]
操作之后得到NX维度的矩阵用以推理打分(可以近似的看作神经网络里加上了全连接层,原先N个向量(M长度)经过全链接层得到N个长度为X的向量),然后向量之间做所谓的相似度用以推理分数。
def standEst(dataMat, user, simMeas, item):
n = shape(dataMat)[1]
simTotal = 0.0; ratSimTotal = 0.0
for j in range(n):
userRating = dataMat[user,j]
if userRating == 0: continue
overLap = 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])
print ('the %d and %d similarity is: %f' % (item, j, similarity))
simTotal += similarity
ratSimTotal += similarity * userRating
if simTotal == 0: return 0
else: return ratSimTotal/simTotal
def svdEst(dataMat, user, simMeas, item):
n = shape(dataMat)[1]
simTotal = 0.0; ratSimTotal = 0.0
U,Sigma,VT = la.svd(dataMat)
#print(Sigma)
Sig4 = mat(eye(4)*Sigma[:4]) #arrange Sig4 into a diagonal matrix
#print(Sig4)
xformedItems = dataMat.T * U[:,:4] * Sig4.I #create transformed items
print(dataMat.shape)
print(xformedItems.shape)
for j in range(n):
userRating = dataMat[user,j]
if userRating == 0 or j==item: continue
print(xformedItems[item,:].shape)
similarity = simMeas(xformedItems[item,:].T,\
xformedItems[j,:].T)
print ('the %d and %d similarity is: %f' % (item, j, similarity))
simTotal += similarity
ratSimTotal += similarity * userRating
if simTotal == 0: return 0
else: return ratSimTotal/simTotal
图片压缩
和上述的同理,对Sigma进行裁剪,得到了更小的三个矩阵,拼接最后的结果却能够较好的还原原矩阵
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 vector
SigRecon[k,k] = Sigma[k]
reconMat = U[:,:numSV]*SigRecon*VT[:numSV,:]
print ("****reconstructed matrix using %d singular values******" % numSV)
printMat(reconMat, thresh)