import numpy as np
U, Sigma, VT = np.linalg.svd([[1, 1], [7, 7]])
U
Sigma #Sigma是一个对角矩阵,这样返回是为了节省空间
VT
import svdRec
Data = svdRec.loadExData()
U, Sigma, VT = np.linalg.svd(Data)
Sigma
矩阵分解的原理如下: $$Data_{m \times n} \approx U_{m \times 3} \Sigma_{3 \times 3} V_{3 \times n}^{T}$$
Sigma3 = np.mat([[Sigma[0], 0, 0], [0, Sigma[1], 0], [0, 0, Sigma[2]]])
retMat = U[:,:3] * Sigma3 * VT[:3,:]
retMat[np.abs(retMat)<1e-8] = 0
retMat
reload(svdRec)
myMat = np.mat(svdRec.loadExData())
svdRec.ecludSim(myMat[:,0], myMat[:,4])
svdRec.ecludSim(myMat[:,0], myMat[:,0])
svdRec.cosSim(myMat[:,0], myMat[:,4])
svdRec.cosSim(myMat[:,0], myMat[:,0])
svdRec.pearsSim(myMat[:,0], myMat[:,4])
svdRec.pearsSim(myMat[:,0], myMat[:,0])
reload(svdRec)
myMat = np.mat(svdRec.loadExData())
myMat[0, 1] = myMat[0, 0] = myMat[1, 0] = myMat[2, 0] = 4
myMat[3, 2] = 2
myMat
svdRec.recommend(myMat, 2)
svdRec.recommend(myMat, 2, simMeas=svdRec.ecludSim)
svdRec.recommend(myMat, 2, simMeas=svdRec.pearsSim)
reload(svdRec)
myMat = np.mat(svdRec.loadExData2())
U, Sigma, VT = np.linalg.svd(myMat)
Sigma
Sig2 = Sigma ** 2
Sig2
np.sum(Sig2)
sum(Sig2) * 0.9
sum(Sig2[:2])
sum(Sig2[:3])
所以我们可以将一个11维矩阵转换成一个3维矩阵,使得这三个元素包含的能量高于总能量的90%。svdEst函数中以下语句:
xformedItems = dataMat.T * U[:, :4] * Sig4.I #构建转换后的物品
这条语句就是用来计算矩阵奇异值分解后的$V$矩阵,因此需要先将$Data_{m \times n}$转置成$Data_{m \times n}^{T}$的$n \times m$的矩阵。
reload(svdRec)
svdRec.recommend(myMat, 1, estMethod=svdRec.svdEst)
svdRec.recommend(myMat, 1, estMethod=svdRec.svdEst, simMeas=svdRec.pearsSim)
上述代码的运行效率并不高,一个原因是不必在每次估计评分时都做SVD分解。此外,在上面的矩阵中,含有很多0元素,在实际系统中0元素更多。我们可以只存储非零元素来节省内存和计算开销。另一个潜在的计算资源浪费来自于相似度得分。解决方法可以是离线计算并保存相似度得分。
reload(svdRec)
svdRec.imgCompress(2)