Machine Learning---11--svd

奇异值分解,singular value decomposition(SVD)是线性代数中一种重要的矩阵分解

特征值

对于一个方阵,其特征值和特征向量满足:

Aν=λνAν=λν

求出所有的特征值和特征向量后,就得出了方阵A的特征值分解:

A=QΣQ1

奇异值

现实世界里,为了实现类似特征值分解的计算,我们使用奇异值分解。奇异值分解适用于任何矩阵,如下所示,其中A是一个m*n的矩阵:

A=UmmΣmnVTnnA=Um∗mΣm∗nVn∗nT

其中

  • UU 是一个m*m的正交矩阵,其向量被称为左奇异向量
  • VV 也是一个n*n的正交矩阵,其向量被成为右奇异向量
  • ΣΣ 是一个m*n的矩阵,其对角线上的元素为奇异值,其余元素皆为0

当选取top k个奇异值时,可以将矩阵降维成为:

AmnUmkΣkkVTknAm∗n≈Um∗kΣk∗kVk∗nT

基于SVD的机器学习之Python代码如下:

import numpy as np
from numpy import linalg as la

def loadExData():
    
    data=np.array([[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]])
    return data

def loadExData2():
    data2=np.array([[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]])
    return data2
    

 #计算相似度   
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*np.corrcoef(inA, inB, rowvar = 0)[0][1]

'''
def cosSim(inA,inB):                          #利用余弦相似度计算
    num=float(np.multiply(inA.T,inB))  #错误不知道为啥
    #num = float(inA.T*inB)
    denom = la.norm(inA)*la.norm(inB)
    return 0.5+0.5*(num/denom)
'''

#基于物品相似度的推荐引擎
#1、
def standEst(dataMat, user, simMeas, item):
    #输入:数据集、用户、相似性度量、物品编号
    #输出:用户对物品的估计评分值
    n = np.shape(dataMat)[1]            #得到物品数
    simTotal = 0.0; ratSimTotal = 0.0
    for j in range(n):
        userRating = dataMat[user,j]
        if userRating == 0: continue
        overLap =np. nonzero(np.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

#2、推荐引擎  
def recommend(dataMat, user, N=3, simMeas=ecludSim, estMethod=standEst):
    #输入:数据集、用户、返回个数(默认为3)、相似性度量、评估方法
    #输出:返回相似度最高的N个推荐结果
    unratedItems = np.nonzero(dataMat[user,:].A==0)[1]           #建立未评分的物品列表
    if len(unratedItems) == 0: return 'you rated everything'
    itemScores = []
    for item in unratedItems:
        estimatedScore = estMethod(dataMat, user, simMeas, item) #调用standEst对物品进行评分
        itemScores.append((item, estimatedScore))                #将物品编号与评分值放入列表中
    return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[:N]     #从大到小进行排序,返回前N个值

#3、基于SVD的评分估计    
def svdEst(dataMat, user, simMeas, item):
    n = np.shape(dataMat)[1]
    simTotal = 0.0; ratSimTotal = 0.0
    U,Sigma,VT = la.svd(dataMat)
    Sig4 = np.mat(np.eye(4)*Sigma[:4])    #使用总能量达90%(使用前三个元素)的奇异值构建对角矩阵
    xformedItems = dataMat.T * U[:,:4] * Sig4.I  #利用矩阵U将数据转化到低维空间
    for j in range(n):               #在用户对应行的所有物品上遍历
        userRating = dataMat[user,j]
        if userRating == 0 or j==item: continue
        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

if __name__ == "__main__":
    
    #SVD分解
    Data=loadExData()
    U,Sigma,VT=np.linalg.svd(Data)
    print(Sigma) #只返回对角线的值
    #数据重构--只取前两个奇异值
    Sig2=([Sigma[0],0],[0,Sigma[1]])
    print(Sig2)
    #reconData=U[:,:2]*Sig2*VT[:2,:]
    #print(reconData)
    
    #计算相似度
    p1=ecludSim(Data[:,0],Data[:,4])
    p11=ecludSim(Data[:,0],Data[:,0])
    print(p1,p11)
    print('-----------------------------')
    p2=pearsSim(Data[:,0],Data[:,4])
    p22=pearsSim(Data[:,0],Data[:,0])
    print(p2,p22)
    print('-----------------------------')
    
    ''' 
    p3=cosSim(Data[:,0],Data[:,4])
    p33=cosSim(Data[:,0],Data[:,0])
    print(p3,p33)
    print('-----------------------------')
    '''
    #查看推荐引擎的效果
    print(Data)
    print('-----------------------------')
    Data[0,0]=Data[0,1]=Data[1,0]=Data[2,0]=4
    print(Data)
    Data1=np.mat(Data)   #数组转为矩阵,因为矩阵才可使用.A属性,即dataMat[user,:].A
    print('-----------------------------')
    pre=recommend(Data1,2)  #用户2,即矩阵的第三行
    print(pre)
    print('-----------------------------')
    
    #利用SVD提高推荐效果
    Data2=loadExData2()
    Data2=np.mat(Data2)
    pre2=recommend(Data1,1,simMeas=pearsSim, estMethod=svdEst)
    print(pre2)
    
    '''
    计算奇异值的能量
    Sig2=Sigma**2
    sum(Sig2)      总能量
    sum(Sig2)*0.9  90%的能量
    sum(Sig2[:2])  前两个值能获得的能量
    sum(Sig2[:3])  前三个值能获得的能量
    '''


猜你喜欢

转载自blog.csdn.net/qq_38096703/article/details/78020851