py2.7《机器学习实战》利用SVD简化数据

本文介绍了SVD(奇异值分解)在推荐系统中的应用,包括如何通过SVD简化矩阵来提高推荐精度,以及使用不同相似度度量方法进行物品推荐。文中还提供了Python实现代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、SVD的应用

1.LSI,LSA

2.推荐系统

SVD的本质就是分解矩阵,将分解后的矩阵有效部分提取再结合为新矩阵


二、Python实现SVD

#-*- coding:utf-8 -*-
def loadData():
    return [[1,1,1,0,0],
            [2,2,2,0,0],
            [1,1,1,0,0],
            [5,5,5,0,0],
            [1,1,0,2,2],
            [0,0,0,3,3],
            [0,0,0,1,1]]

#-*- coding:utf-8 -*-
from numpy import *
import svdrec
data = svdrec.loadData()
u,sigma,vt = linalg.svd(data) #利用线代库特征提取
#print sigma 原始矩阵

sig3 = mat([[sigma[0],0,0],[0,sigma[1],0],[0,0,sigma[2]]]) #只有前三个有用,重构原始矩阵 , sigma
print u[:,:3]*sig3*vt[:3,:] #极小值可以看为0,这里就是用了SVD的公式,并且是缩减了特征值,只要了前三列,前3行3列,和前三行

三、基于协同过滤的推荐引擎

1.相似度的计算(这里尝试使用欧氏距离,皮尔逊相关系数,余弦相似度三种方法)

#三种相似度计算方法,这里假设inA和inB都是列向量
def eulidASim(inA,inB):
        return 1.0/(1.0+la.norm(inA-inB)) #这里运用了欧氏距离,方便相似度值再0~1之间变化

def pearsSim(inA,inB):
        if len(inA) < 3 : return 1.0 #会检测是否存在3个点以上,如果不存在则认为两个向量完全相关
        return 0.5+0.5*corrcoef(inA,inB,rowvar=0)[0][1] #皮尔逊相关系数:取值范围归一化到0~1之间,以向量计算

def cosSim(inA,inB):
        num = float(inA.T*inB)
        denom = la.norm(inA)*la.norm(inB) #这里是默认为2范数
        return 0.5+0.5*(num/denom) #余弦相似度
(1)对欧氏距离的测试

#-*- coding:utf-8 -*-
from numpy import *
import svdrec
myMat = mat(svdrec.loadExData())
print "第一列和第五列的比较答案为:",svdrec.eulidASim(myMat[:,0],myMat[:,4]) #比较第一列和第五列,会存在很小的误差
print "第一列和第一列的比较答案为:",svdrec.eulidASim(myMat[:,0],myMat[:,0])
测试结果:
第一列和第五列的比较答案为: 0.1336766024
第一列和第一列的比较答案为: 1.0


(2)对余弦相似测试:

#-*- coding:utf-8 -*-
from numpy import *
import svdrec
myMat = mat(svdrec.loadExData())
print "第一列和第五列的比较答案为:",svdrec.cosSim(myMat[:,0],myMat[:,4]) 
print "第一列和第一列的比较答案为:",svdrec.cosSim(myMat[:,0],myMat[:,0])
测试结果:

第一列和第五列的比较答案为: 0.547245559126
第一列和第一列的比较答案为: 1.0


(3)对皮尔逊系数相似度的测试:

#-*- coding:utf-8 -*-
from numpy import *
import svdrec
myMat = mat(svdrec.loadExData())
print "第一列和第五列的比较答案为:",svdrec.pearsSim(myMat[:,0],myMat[:,4])
print "第一列和第一列的比较答案为:",svdrec.pearsSim(myMat[:,0],myMat[:,0])
测试结果:

第一列和第五列的比较答案为: 0.237686194076
第一列和第一列的比较答案为: 1.0


2.基于物品相似度的推荐引擎

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 #如果该物品评分为0,那么认为用户没有对物品评分
                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])
                simTotal+=similarity
                ratSimTotal+=similarity*userRating #相似度和用户的成绩
        if simTotal ==0 : return 0 #相似度为0终止这次循环
        else : return ratSimTotal/simTotal#利用归一化

def recommend(dataMat,user,N=3,simMeans=cosSim,estMethod=standEst):
        #矩阵,用户,默认推荐前三个,默认采用余弦相似度,默认采用standEst估计方法
        unratedItems = nonzero(dataMat[user,:].A==0)[1]  #建立一个没有评分的表
        if len(unratedItems)==0 : return 'you rated everything' #不存在没有评分的物品就退出函数
        itemScores = []
        for item in unratedItems: #对每个没有评分的物品进行评分
                estimatedScore = estMethod(dataMat,user,simMeans,item)
                itemScores.append((item,estimatedScore)) #得出物品和物品的分数
        return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[:N]

测试样例:

#-*- coding:utf-8 -*-
from numpy import *
import svdrec
myMat = mat(svdrec.loadExData())
myMat[0,1] = myMat[0,0] = myMat[1,0] = myMat[2,0] = 4
myMat[3,3] = 2
print svdrec.recommend(myMat,2) 
结果:

[(2, 2.5), (1, 2.0243290220056256)]
#表明用户2对物品2的评分为2.5,对物品1的评价为2.02



注:

这里我们认为,行代表用户,列代表物品样式

3.用SVD优化推荐效果

先计算奇异值达到总能量的多少,然后考虑最好降维至多少,这里得出的结论是三维最合适

(1)基于svd的评分估计

def svdEst(dataMat, user, simMeas, item):
    n = shape(dataMat)[1] #求出个数
    simTotal = 0.0; ratSimTotal = 0.0
    U,Sigma,VT = la.svd(dataMat) #svd分解
    Sig4 = mat(eye(4)*Sigma[:4]) #建立对角矩阵
    xformedItems = dataMat.T * U[:,:4] * Sig4.I  #构建转换后的物品
    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

测试代码:

#-*- coding:utf-8 -*-
from numpy import *
import svdrec
myMat = mat(svdrec.loadExData2())
print svdrec.recommend(myMat,1,estMethod=svdrec.svdEst)
效果:

the 0 and 3 similarity is: 0.490950
the 0 and 5 similarity is: 0.484274
the 0 and 10 similarity is: 0.512755
the 1 and 3 similarity is: 0.491294
the 1 and 5 similarity is: 0.481516
the 1 and 10 similarity is: 0.509709
the 2 and 3 similarity is: 0.491573
the 2 and 5 similarity is: 0.482346
the 2 and 10 similarity is: 0.510584
the 4 and 3 similarity is: 0.450495
the 4 and 5 similarity is: 0.506795
the 4 and 10 similarity is: 0.512896
the 6 and 3 similarity is: 0.743699
the 6 and 5 similarity is: 0.468366
the 6 and 10 similarity is: 0.439465
the 7 and 3 similarity is: 0.482175
the 7 and 5 similarity is: 0.494716
the 7 and 10 similarity is: 0.524970
the 8 and 3 similarity is: 0.491307
the 8 and 5 similarity is: 0.491228
the 8 and 10 similarity is: 0.520290
the 9 and 3 similarity is: 0.522379
the 9 and 5 similarity is: 0.496130
the 9 and 10 similarity is: 0.493617
[(4, 3.3447149384692283), (7, 3.3294020724526971), (9, 3.328100876390069)] #表明对4,7,9物品的评价





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kelisita

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值