【Python机器学习】利用SVD简化数据——示例:菜肴推荐引擎

news2024/12/29 9:23:40

现在,构建一个推荐引擎,该推荐引擎关注的是餐馆食物的推荐。假设一个人决定外出吃饭,但并不知道去哪吃什么,我们这个推荐系统就可以帮他做到这两点。

首先我们构建一个基本的推荐引擎,它能够寻找用户没有尝过的菜肴,然后,通过SVD来减少特征空间并提高推荐的效果。这之后,将程序打包并通过用户可读的人机界面提供给人们使用。最后,我们可以看构建推荐系统时会面临的一些问题。

推荐未尝过的菜肴

推荐系统的工作过程一般是:给定一个用户,系统会为此用户返回N个最好的推荐菜。为了实现这一点,则需要我们做到:

1、寻找用户没有评级的菜肴,即在用户-物品矩阵中的0值;

2、在用户没有评级的所有物品中,对每个物品预计一个可能的评级分数。这就是说,我们认为用户可能会对物品的打分(这就是相似度计算的初衷);

3、对这些物品的评分从高到低进行排序,返回前N个物品。

接下来,是具体的代码实现:

from numpy import *
from numpy import linalg as la


def cosSim(inA,inB):
        num=float(inA.T*inB)
        denom=la.norm(inA)*la.norm(inB)
        return 0.5+0.5*(num/denom)

#用来计算在给定相似度计算方法的条件下,用户对物品的估计评分值
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=simTotal+similarity
                ratSimTotal=ratSimTotal+similarity*userRating
        if simTotal==0:
                return 0
        else:
                return ratSimTotal/simTotal
#推荐引擎,它会调用standEst()函数
def recommend(dataMat,user,N=3,simMeas=cosSim,estMethod=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,simMeas,item)
                itemScores.append((item,estimatedScore))
        return sorted(itemScores,key=lambda jj:jj[1],reverse=True)[:N]



上述代码包含了两个函数:第一个是standEst(),用来计算在给定相似度计算方法的条件下,用户对物品的估计评分值。第二个函数是recommend(),也就是推荐引擎,它会调用standEst()函数。

standEst()函数的输入参数包括数据矩阵、用户编号、物品编号、相似度计算方法。假设这里的数据矩阵的形式为行对应用户、列对应物品。那么,我们首先会得到数据集中的物品数目,然后对两个后面用于计算估计评分值的变量进行初始化。接着,我们遍历行中的每个物品。如果某个物品评分值为0,就意味着用户没有对该物品评分,跳过了这个物品。该循环大体上是对用户评过分的每个物品进行遍历,并将它和其他物品进行比较。变量overLap给出的是两个物品当中已经被评分的那个元素。如果两个没有任何重合元素,则相似度为0且中止本次循环。但是如果存在重合的物品,则基于这些重合物品计算相似度。随后,相似度会不断累加,每次计算时还考虑相似度和当前用户评分的乘积。最后,通过除以所有的评分总和,对上述相似度评分的乘积进行归一化。这就可以使得最后的评分值在0到5之间,而这些评分值则用于对预测值进行排序。

函数recommend()产生了最高的N个推荐结果。如果不指定N的大小,则默认值为3。该函数另外的参数还包括相似度计算方法和估计方法。我们可以使用任一种相似度计算方法。函数第一件事就是对给定用户建立一个未评分的物品列表。如果不存在未评分物品,那么就退出函数;否则,在所有的未评分物品上进行循环。对每个未评分物品,则通过调用standEst()来产生该物品的预测得分。该物品的编号和估计得分值会放在一个元素列表itemScores中。最后按照估计得分,对该列表进行排序并返回。该列表是从小到大逆序排列的。因此其第一个值就是最大值。

观察实际运行效果:

首先,原始数据:

def loadExData():
    return [[4,4,0,2,2],
            [4,0,0,3,3],
            [4,0,0,1,1],
            [1,1,1,2,0],
            [2,2,2,0,0],
            [1,1,1,0,0],
            [5,5,5,0,0]]

现在尝试默认的推荐:

mymat=mat(loadExData())
print(recommend(mymat,2))

这代表用户2对物品2的预测评分值为2.5,对物品1的预测评分值为2.05。下面我们就利用其他的相似度计算方法来进行推荐:

print(recommend(mymat,2,simMeas=euclidSim))
print(recommend(mymat,2,simMeas=pearsSim))

我们可以对多个用户进行尝试,或者对数据集做些修改来了解其给预测结果带来的变化。

利用SVD提高推荐的效果

实际的数据集会比我们用于展示recommend()函数功能的mymat矩阵稀疏的多。比如下图的数据集:

我们可以将该矩阵输入到程序中,下面来计算该矩阵的SVD来了解其到底需要多少维特征:

def loadExData2():
    return[[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]]
U,Sigma,VT=la.svd(loadExData2())
print('Sigma:',Sigma)

接下来看到底有多少个奇异值能达到总能量的90%,首先对Sigma的值求平方,然后计算总能量计总能量的90%:

Sig2=Sigma**2
print(sum(Sig2)*0.9)

计算前两个元素所包含的能量:

print(sum(Sig2[:2]))

该值低于总能量的90%,所以改为计算前三个元素所包含的能量:

print(sum(Sig2[:3]))

这次高于总能量的90%,然后,我们可以将一个11维的矩阵转换成一个3维的矩阵。下面对转换后的三维空间构造出一个相似度计算函数。我们利用SVD将所有的菜肴映射到一个低维空间中区。在低维空间下,可以利用之前相同的相似度计算方法来进行推荐:

def svdEst(dataMat,user,simMeas,item):
    n=shape(dataMat)[1]
    simTotal=0.0
    ratSimTotsl=0.0
    U, Sigma, VT = la.svd(loadExData2())
    Sig4=mat(eye(4)*Sigma[:4])
    xformdItems=dataMat.T*U[:,:4]*Sig4.I
    for j in range(n):
        userRating=dataMat[user,j]
        if userRating==0 or j==item:
            continue
        similarity=simMeas(xformdItems[item,:].T,xformdItems[j,:].T)
        print('the %d and %d similarity is : %f' % (item, j, similarity))
        simTotal=simTotal+similarity
        ratSimTotsl=ratSimTotsl+similarity*userRating
        if simTotal==0:
            return 0
        else:
            return ratSimTotsl/simTotal

上述代码中只有一个函数svdEst()。在recommend()中,这个函数用于替换对standEst()的调用,该函数对给定用户给定物品构建了一个评分估计值。这个函数的第三行对数据集进行了SVD分解。在SVD分解之后,我们只利用包含了90%能量值的奇异值,这些奇异值会以NumPy数组的形式得以保存。因此如果要进行矩阵运算,那么就必须要用这些奇异值构建出一个对角矩阵,然后,利用U矩阵将物品转换到低维空间中。

对于给定的用户,for循环在用户对应行的所有元素上进行遍历。这和standEst()函数中的for循环的目的一样,只不过这里的相似度计算是在低维空间下进行的。相似度的计算方法也会作为一个参数传递给该函数。然后,我们对相似度求和,同时对相似度及对应评分值的乘积求和。这些值返回之后则用于估计评分的计算。

下面是程序的执行效果:

myMat=mat(loadExData2())
print(recommend(myMat,1,estMethod=svdEst))

以另一种相似度计算方法测试:

myMat=mat(loadExData2())
print(recommend(myMat,1,estMethod=svdEst,simMeas=pearsSim))

构建推荐引擎面临的调整

上面的代码很好的展示出了推荐引擎的工作流程以及SVD将数据映射为重要特征的过程。

但推荐引擎还存在其他很多规模扩展的调整性问题,比如矩阵的表示方法:实际系统中的0非常多,也许我们可以通过只存储非零元素来节省内存和计算开销。另一个潜在的计算资源莱菲则来自于相似度得分,普遍的做法是离线计算并保存相似度得分。

推荐引擎面临的另一个问题是如何在缺乏数据时给出好的推荐,这称为冷启动问题,处理起来十分困难。这个问题的另一个说法是,用户不会喜欢一个无效的物品,而用户不喜欢的物品又无效。

冷启动问题的解决方案,就是将推荐看成是搜索问题,在内部表现上,不同的解决办法虽然有所不同,但是对用户而言都是透明的。为了将推荐看成是搜索问题,我们可能要使用所需要推荐物品的属性。同时,我们也可以将这些属性作为相似度计算所需要的数据,这被称为基于内容的推荐。可能,基于内容的推荐并不如基于协同过滤的推荐效果好,但它是一个良好的开始。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2051039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++(11)类语法分析(2)

C(10)之类语法分析(2) Author: Once Day Date: 2024年8月17日 一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦… 漫漫长路,有人对你微笑过嘛… 全系列文章可参考专栏: 源码分析_Once-Day的博客-CSDN博客 …

有关缓存的一些面试知识

1、讲一讲Redis各种数据类型与底层实现 底层数据结构一共有 7 种,分别是简单动态字符串、双向链表、压缩列表、哈希表、跳表和整数数组、快速列表。它们和数据类型的对应关系如下图所示 String 类型的底层实现只有一种数据结构,也就是简单动态字符串。而…

57qi5rW35LqRZUhS pc.mob SQL注入漏洞复现

0x01 产品简介 57qi5rW35LqRZUhS是大中型企业广泛采用人力资源管理系统。某云是国内顶尖的HR软件供应商,是新一代eHR系统的领导者。 0x02 漏洞概述 57qi5rW35LqRZUhS pc.mob 接口存在SQL注入漏洞,未经身份验证的远程攻击者除了可以利用 SQL 注入漏洞获取数据库中的信息(例…

Linux-LVM创建和扩容

文章目录 1. 直接上手1.2 LVM 概念1.2.1 关键术语 1.3 LVM使用步骤1.3.1 创建物理卷(PV)1.3.2 创建卷组(VG)1.3.3 创建逻辑卷(LV)1.3.4 格式化逻辑卷1.3.5 挂载逻辑卷1.3.6 扩展和缩小逻辑卷1.3.6.1 扩展逻辑卷1.3.6.2…

Science Robotics 受螳螂视觉启发的立体人工复眼技术及其边缘计算应用

在自然界中,生物体的独特生理结构和功能一直是人类技术创新的灵感源泉。节肢动物,尤其是昆虫类生物,高效的视觉系统吸引了众多研究者的关注。所有昆虫当中,螳螂因其独特的视觉机制(左眼和右眼视野重叠形成的立体视觉&a…

网络编程项目篇

一、tftp客户端下载 1)tftp协议概述 简单文件传输协议,适用于在网络上进行文件传输的一套标准协议,使用UDP传输 特点: 是应用层协议 基于UDP协议实现 数据传输模式 octet:二进制模式(常用&#xff0…

【SpringBoot】SpringBoot中分页插件(PageHelper)的使用

目录 1.分页概念 2.原生写法 3.PageHelper插件分页查询 3.1 介绍 3.2 使用 3.3 Page对象和PageInf对象 1.分页概念 用户查询的数据不可能一次性全部展示给用户(如果用户有一万条数据呢),而是分页展示给用户,这就是分页查询。…

Hospital Information System (HIS)

Hospital Information System (HIS) 医院门诊就诊流程

快速体验Ollama安装部署并支持AMD GPU推理加速

序言 Ollama 是一个专注于本地运行大型语言模型(LLM)的框架,它使得用户能够在自己的计算机上轻松地部署和使用大型语言模型,而无需依赖昂贵的GPU资源。Ollama 提供了一系列的工具和服务,旨在简化大型语言模型的安装、…

深入理解JVM运行时数据区(内存布局 )5大部分 | 异常讨论

前言: JVM运行时数据区(内存布局)是Java程序执行时用于存储各种数据的内存区域。这些区域在JVM启动时被创建,并在JVM关闭时销毁。它们的布局和管理方式对Java程序的性能和稳定性有着重要影响。 目录 一、由以下5大部分组成 1.…

【html+css 绚丽Loading】 - 000004 玄天旋轮

前言:哈喽,大家好,今天给大家分享htmlcss 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 &#x1f495…

STM32 编码器模式详解

编码器模式 stm32的定时器带的也有编码器模式。 所用的编码器是有ABZ三相,其中ab相是用来计数,z相输出零点信号。 AB相根据旋转的方向不同,输出的波形如下图所示: 从图上可以看出来,cw方向A相会超前B相90度左右&#…

egret 拖尾的实现 MotionStreak

背景:egret项目中需要用到拖尾效果,引擎原生没有提供,参考cocos2dx 的 MotionStreak实现拖尾效果。 原理 拖尾的原理很简单,定时记录节点的位置,根据运行的轨迹和指定的拖尾宽度生成拖尾网格,然后将纹理绘…

VS2019开发跨平台(Linux)程序时,怎么配置第三方库的路径

一、问题描述: 使用跨平台编译时,VS2019总是提示链接openssl库有问题; 二、错误时的配置: 1、前提 openssl在Linux系统默认下是1.0.0版本,而自己准备好的是1.1.1版本,并且路径完全不在一个地方&#xf…

【Linux-进程】系统初识:冯诺依曼体系结构

系列文章:《Linux入门》 目录 冯诺依曼体系结构 1)硬件上 🌷1.什么是冯诺依曼体系结构? 🌷2.冯诺依曼结构的五个主要组成部分 1.运算器 2.控制器 3.存储器 4.输入输出 设备 ⁉️3.为什么还需要内存呢&#xf…

c++数据结构算法复习基础-- 4 -- 线性表-单向循环链表-常用操作接口-复杂度分析

1、单向循环链表一 1)特点 每一个节点除了数据域,还有一个next指针域指向下一个节点(存储了下一个节点的地址) 末尾节点的指针域指向了头节点 析构函数思路图 2)代码实现 //定义结点 //单向循环链表 class CircleLink { public://构造函数…

使用python基于fastapi发布接口(一)

FastAPI官网地址 FastAPI基于Python 3.6+和Starlette框架,天生就带着高性能和异步的基因。 FastAPI的文档生成功能简直是开发者的福音! 你不再需要手动编写API文档,FastAPI能自动帮你搞定。 FastAPI还超级灵活,支持各种数据库和认证方式,无论是SQLite、PostgreSQL还是M…

【xilinx】TPM可信平台模块与 Zynq UltraScale+ PS SPI 接口

本博客(Venu Inaganti)介绍了可信平台模块 (TPM) 与 Zynq UltraScale PS SPI 控制器的连接。 目前唯一具有 TPM 的评估板是 KR260/KV260 SOM,因此为了帮助正在试验 Zynq UltraScale 设备的用户,本文介绍了如何通过 PMOD 连接器与…

【MongoDB】Java连接MongoDB

连接URI 连接 URI提供驱动程序用于连接到 MongoDB 部署的指令集。该指令集指示驱动程序应如何连接到 MongoDB,以及在连接时应如何运行。下图解释了示例连接 URI 的各个部分: 连接的URI 主要分为 以下四个部分 第一部分 连接协议 示例中使用的 连接到具有…

计算机视觉中的上采样与下采样:深入浅出实例代码解析

文章目录 一、引言二、下采样(Downsampling)三、上采样(Upsampling)1. 最近邻插值2.双线性插值3.转置卷积(Deconvolution)4.代码部分 四、总结 在计算机视觉领域,尤其是在深度学习和卷积神经网络…