计算机设计大赛 推荐系统设计与实现 协同过滤推荐算法

0 前言

🔥 优质竞赛项目系列,今天要分享的是

🚩 推荐系统设计与实现

该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!

🥇学长这里给一个题目综合评分(每项满分5分)

  • 难度系数:3分
  • 工作量:3分
  • 创新点:4分

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

简介

推荐系统,是当今互联网背后的无名英雄。

我们在某宝首页看见的商品,某条上读到的新闻,某度上的搜索列表,甚至在各种地方看见的广告,都有赖于推荐算法和系统.

本片文章讲述有哪些常用的推荐算法, 协同过滤推荐算法的原理, 以及如何使用协同过滤算法设计一个商品推荐系统.

常见推荐算法
协同过滤

协同过滤(Collaborative
Filtering)作为推荐算法中最经典的类型,包括在线的协同和离线的过滤两部分。所谓在线协同,就是通过在线数据找到用户可能喜欢的物品,而离线过滤,则是过滤掉一些不值得推荐的数据,比比如推荐值评分低的数据,或者虽然推荐值高但是用户已经购买的数据。

协同过滤的模型一般为m个物品,m个用户的数据,只有部分用户和部分数据之间是有评分数据的,其它部分评分是空白,此时我们要用已有的部分稀疏数据来预测那些空白的物品和数据之间的评分关系,找到最高评分的物品推荐给用户。

一般来说,协同过滤推荐分为三种类型。第一种是基于用户(user-based)的协同过滤,第二种是基于项目(item-
based)的协同过滤,第三种是基于模型(model based)的协同过滤。

基于用户的协同过滤的基本原理是,根据所有用户对物品或者信息的偏好,发现与当前用户口味和偏好相似的用户群,然后基于这些用户的历史偏好,为当前用户进行推荐。

在这里插入图片描述
假设用户A喜欢物品A、物品C,用户B喜欢物品B,用户C喜欢物品A、物品C和物品D。从这些用户的历史偏好中,我们可以看出用户A和用户C的偏好是类似的。同时我们可以看到用户C喜欢物品D,所以我们可以猜想用户A可能也喜欢物品D,因此可以把物品D推荐给用户A。

分解矩阵

这是一个非常优雅的推荐算法,因为当涉及到矩阵分解时,我们通常不会太多地去思考哪些项目将停留在所得到矩阵的列和行中。但是使用这个推荐引擎,我们清楚地看到,u是第i个用户的兴趣向量,v是第j个电影的参数向量。

在这里插入图片描述
所以我们可以用u和v的点积来估算x(第i个用户对第j个电影的评分)。我们用已知的分数构建这些向量,并使用它们来预测未知的得分。

例如,在矩阵分解之后,Ted的向量是(1.4; .8),商品A的向量是(1.4; .9),现在,我们可以通过计算(1.4; .8)和(1.4;
.9)的点积,来还原商品A-Ted的得分。结果,我们得到2.68分。

在这里插入图片描述

聚类

上面两种算法都极其简单,适用于小型系统。在这两种方法中,我们把推荐问题当做一个有监督机器学习任务来解决。

现在,该开始用无监督学习来解决问题了。

假设我们正在建立一个大型推荐系统,这时协同过滤和矩阵分解花费的时间更长了。第一个浮现在脑海里的解决之道,就是聚类。

业务开展之初,缺乏之前的用户数据,聚类将是最好的方法。

不过,聚类是一种比较弱的个性化推荐,因为这种方法的本质是识别用户组,并对这个组内的用户推荐相同的内容。

当我们有足够数据时,最好使用聚类作为第一步,来缩减协同过滤算法中相关邻居的选择范围。这个方法还能挺高复杂推荐系统的性能。

每个聚类都会根据其中用户的偏好,来分配一组典型的偏好。每个聚类中的用户,都会收到为这个聚类计算出的推荐内容。

深度学习

在过去的十年中,神经网络已经取得了巨大的飞跃。如今,神经网络已经得以广泛应用,并逐渐取代传统的机器学习方法。

接下来,我要介绍一下YouTube如何使用深度学习方法来做个性化推荐。

毫无疑问,由于体量庞大、动态库和各种观察不到的外部因素,为YouTube用户提供推荐内容是一项非常具有挑战性的任务。

根据《Deep Neural Networks for YouTube Recommendations》(
https://static.googleusercontent.com/media/research.google.com/ru//pubs/archive/45530.pdf
),YouTube的推荐系统算法由两个神经网络组成:一个用于候选生成,一个用于排序。如果你没时间仔细研究论文,可以看看我们下面给出的简短总结。

在这里插入图片描述
以用户的浏览历史为输入,候选生成网络可以显著减小可推荐的视频数量,从庞大的库中选出一组最相关的视频。这样生成的候选视频与用户的相关性最高,然后我们会对用户评分进行预测。

这个网络的目标,只是通过协同过滤提供更广泛的个性化。

在这里插入图片描述
进行到这一步,我们得到一组规模更小但相关性更高的内容。我们的目标是仔细分析这些候选内容,以便做出最佳的选择。

这个任务由排序网络完成。

所谓排序就是根据视频描述数据和用户行为信息,使用设计好的目标函数为每个视频打分,得分最高的视频会呈献给用户。
在这里插入图片描述
通过这两步,我们可以从非常庞大的视频库中选择视频,并面向用户进行有针对性的推荐。这个方法还能让我们把其他来源的内容也容纳进来。
在这里插入图片描述
推荐任务是一个极端的多类分类问题。这个预测问题的实质,是基于用户(U)和语境©,在给定的时间t精确地从库(V)中上百万的视频类(i)中,对特定的视频观看(Wt)情况进行分类。

协同过滤原理

使用基于物品的协同过滤,需要维护一个物品相似度矩阵;使用基于用户的协同过滤,需要维护一个用户相似度矩阵。
在这里插入图片描述
两用户之间的相似度的计算其实很简单,用户i与用户j的相似度 = (i、j都打开过的网页数)/根号(i打开过的网页数 *
j打开过的网页数)。这个计算与“基于物品的协同过滤”中的物品之间相似度的计算是类似的。

在这里插入图片描述

上面是一个用户相似度计算的案例。我们试着计算A和D之间的相似度。从“用户打开过的网页”可以看出,A和D都打开过的网页只有d,也就是1个。用户A打开过的网页数=3,用户D打开过的网页数=3。所以A和D的相似度=1/根号(3*3)。其他的计算也是类似的。

有了用户之间的相似度之后,就可以计算推荐度了。假设e是刚刚发布的文章,这时候用户B、C、D都浏览到e新闻的标题,其中C、D点击了,我们就可以计算A对e的兴趣度。

A对e的兴趣度=A与B的相似度 B对e的兴趣度 + A与C的相似度 C对e的兴趣度 + A与D的相似度*D对e的兴趣度。
因为我们这里用的不是评分制,而是考虑是否点击,那么D点击了e,D对e的兴趣度=1。

A对e的兴趣度 = 1/根号(6)*1 + 1/根号(6)*1 + 1/根号(9)*1

所以,比如100篇新的文章出来之后,对部分用户进行了曝光,然后就可以根据用户相似度,来预计其他用户对这篇文章的兴趣度,进而挑选这100篇中预计兴趣度最高的30篇曝光给这群用户。

系统设计
示例代码(py)



    from abc import ABCMeta, abstractmethod
    import numpy as np
    from collections import defaultdict


    class CF_base(metaclass=ABCMeta):
        def __init__(self, k=3):
            self.k = k
            self.n_user = None
            self.n_item = None
    
        @abstractmethod
        def init_param(self, data):
            pass
    
        @abstractmethod
        def cal_prediction(self, *args):
            pass
    
        @abstractmethod
        def cal_recommendation(self, user_id, data):
            pass
    
        def fit(self, data):
            # 计算所有用户的推荐物品
            self.init_param(data)
            all_users = []
            for i in range(self.n_user):
                all_users.append(self.cal_recommendation(i, data))
            return all_users


    class CF_knearest(CF_base):
        """
        基于物品的K近邻协同过滤推荐算法
        """
    
        def __init__(self, k, criterion='cosine'):
            super(CF_knearest, self).__init__(k)
            self.criterion = criterion
            self.simi_mat = None
            return
    
        def init_param(self, data):
            # 初始化参数
            self.n_user = data.shape[0]
            self.n_item = data.shape[1]
            self.simi_mat = self.cal_simi_mat(data)
            return
    
        def cal_similarity(self, i, j, data):
            # 计算物品i和物品j的相似度
            items = data[:, [i, j]]
            del_inds = np.where(items == 0)[0]
            items = np.delete(items, del_inds, axis=0)
            if items.size == 0:
                similarity = 0
            else:
                v1 = items[:, 0]
                v2 = items[:, 1]
                if self.criterion == 'cosine':
                    if np.std(v1) > 1e-3:  # 方差过大,表明用户间评价尺度差别大需要进行调整
                        v1 = v1 - v1.mean()
                    if np.std(v2) > 1e-3:
                        v2 = v2 - v2.mean()
                    similarity = (v1 @ v2) / np.linalg.norm(v1, 2) / np.linalg.norm(v2, 2)
                elif self.criterion == 'pearson':
                    similarity = np.corrcoef(v1, v2)[0, 1]
                else:
                    raise ValueError('the method is not supported now')
            return similarity
    
        def cal_simi_mat(self, data):
            # 计算物品间的相似度矩阵
            simi_mat = np.ones((self.n_item, self.n_item))
            for i in range(self.n_item):
                for j in range(i + 1, self.n_item):
                    simi_mat[i, j] = self.cal_similarity(i, j, data)
                    simi_mat[j, i] = simi_mat[i, j]
            return simi_mat
    
        def cal_prediction(self, user_row, item_ind):
            # 计算预推荐物品i对目标活跃用户u的吸引力
            purchase_item_inds = np.where(user_row > 0)[0]
            rates = user_row[purchase_item_inds]
            simi = self.simi_mat[item_ind][purchase_item_inds]
            return np.sum(rates * simi) / np.linalg.norm(simi, 1)
    
        def cal_recommendation(self, user_ind, data):
            # 计算目标用户的最具吸引力的k个物品list
            item_prediction = defaultdict(float)
            user_row = data[user_ind]
            un_purchase_item_inds = np.where(user_row == 0)[0]
            for item_ind in un_purchase_item_inds:
                item_prediction[item_ind] = self.cal_prediction(user_row, item_ind)
            res = sorted(item_prediction, key=item_prediction.get, reverse=True)
            return res[:self.k]

    class CF_svd(CF_base):
        """
        基于矩阵分解的协同过滤算法
        """
    
        def __init__(self, k=3, r=3):
            super(CF_svd, self).__init__(k)
            self.r = r  # 选取前k个奇异值
            self.uk = None  # 用户的隐因子向量
            self.vk = None  # 物品的隐因子向量
            return
    
        def init_param(self, data):
            # 初始化,预处理
            self.n_user = data.shape[0]
            self.n_item = data.shape[1]
            self.svd_simplify(data)
            return data
    
        def svd_simplify(self, data):
            # 奇异值分解以及简化
            u, s, v = np.linalg.svd(data)
            u, s, v = u[:, :self.r], s[:self.r], v[:self.r, :]  # 简化
            sk = np.diag(np.sqrt(s))  # r*r
            self.uk = u @ sk  # m*r
            self.vk = sk @ v  # r*n
            return
    
        def cal_prediction(self, user_ind, item_ind, user_row):
            rate_ave = np.mean(user_row)  # 用户已购物品的评价的平均值(未评价的评分为0)
            return rate_ave + self.uk[user_ind] @ self.vk[:, item_ind]  # 两个隐因子向量的内积加上平均值就是最终的预测分值
    
        def cal_recommendation(self, user_ind, data):
            # 计算目标用户的最具吸引力的k个物品list
            item_prediction = defaultdict(float)
            user_row = data[user_ind]
            un_purchase_item_inds = np.where(user_row == 0)[0]
            for item_ind in un_purchase_item_inds:
                item_prediction[item_ind] = self.cal_prediction(user_ind, item_ind, user_row)
            res = sorted(item_prediction, key=item_prediction.get, reverse=True)
            return res[:self.k]

    if __name__ == '__main__':
        # data = np.array([[4, 3, 0, 5, 0],
        #                  [4, 0, 4, 4, 0],
        #                  [4, 0, 5, 0, 3],
        #                  [2, 3, 0, 1, 0],
        #                  [0, 4, 2, 0, 5]])
        data = np.array([[3.5, 1.0, 0.0, 0.0, 0.0, 0.0],
                         [2.5, 3.5, 3.0, 3.5, 2.5, 3.0],
                         [3.0, 3.5, 1.5, 5.0, 3.0, 3.5],
                         [2.5, 3.5, 0.0, 3.5, 4.0, 0.0],
                         [3.5, 2.0, 4.5, 0.0, 3.5, 2.0],
                         [3.0, 4.0, 2.0, 3.0, 3.0, 2.0],
                         [4.5, 1.5, 3.0, 5.0, 3.5, 0.0]])
        # cf = CF_svd(k=1, r=3)
        cf = CF_knearest(k=1)
        print(cf.fit(data))


系统展示
系统界面

在这里插入图片描述

推荐效果

在这里插入图片描述

最后

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IDEA jdk版本切换问题

打开 IntelliJ IDEA 的 Project Structure(快捷键通常是 Ctrl Alt Shift S)。 转到 Project Settings > Modules。 选择相应的模块,然后在 Sources 标签页下,查看 Language level 是否设置为 自己需要的jdk版本语言。 接…

Java开发分析中文 ---- JProfiler 13

JProfiler 13是一款专业的Java应用程序性能分析工具,可以快速诊断和优化Java应用程序的性能问题。它支持多种操作系统和应用服务器,提供实时性能监控、CPU分析、内存分析、线程分析和数据库访问分析等功能。使用JProfiler 13可以深入了解应用程序的性能和…

PyQT5环境搭建与入门操作(超详细图解安装)

PyQt5软件简介 PyQt5官方版是一款专业优秀的编程工具。PyQt5最新版需要配合Python使用,是Qt C跨平台应用程序框架和跨平台解释语言Python的结合,支持Windows、OS X、Linux、iOS和Android平台运行。PyQt5软件可以帮助用户从Qt Designer生成Python代码&am…

C语言“%”运算符是否可以对小数进行运算?

一、问题 “&#xff05;”运算符是否可以对⼩数进⾏运算&#xff1f; 二、解答 “&#xff05;”运算符&#xff0c;称为求余运算符或者模运算符&#xff0c;要求“&#xff05;”两侧都为整型数据&#xff0c;否则将会产⽣错误 #include <stdio.h> int main() {floa…

【性能问题】postman接口测试偶现高延时排查

一、背景 负责的项目&#xff0c;在test环境&#xff0c;postman连续发送两次接口请求&#xff0c;第二次响应时间高达34s&#xff0c;该现象经常出现&#xff0c;影响QA测试执行效率。这种想象持续一段时间了&#xff0c;今天终于忍无可忍&#xff0c;向Dev和SRE发出求助信息…

AI特训一:为什么要学习AI

我们先了解什么是AI AI&#xff08;人工智能&#xff09;是指计算机系统经过学习和推理能够模拟人类智能行为的一种技术。AI利用机器学习、深度学习、自然语言处理等技术&#xff0c;能够分析大量的数据、识别模式、做出决策和预测 AI有哪些强大之处 处理大量数据&#xff1a…

关于 PostgreSQL,你了解多少

背景 最近因工作原因&#xff0c;了解到了阿里的 hologre&#xff0c;它只支持 psql 协议&#xff0c;用起来跟 mysql 会差很多&#xff0c;也很不习惯。所以就好奇&#xff0c;为啥放着mysql不用&#xff0c;却用 psql 什么是 psql psql 是 开源的关系型数据库管理系统 Pos…

关于msvcp140_1.dll丢失的解决方法分析,一键修复msvcp140_1.dll

随着技术的迭代更新&#xff0c;我们对操作系统变得越发依赖。不过&#xff0c;在使用中有时也会遇到技术障碍&#xff0c;诸如遇到 MSVCP140_1.dll 文件不见的情况。本文着重讨论此问题&#xff0c;并展示了若干解决办法&#xff0c;以便教导用户应对及修补MSVCP140_1.dll文件…

拒掉了一个双 985 的面试者

下班路上&#xff0c;和一个大佬聊天&#xff0c;他说今天面试&#xff0c;拒掉了一个双 985 的候选人。 候选人背景很好&#xff0c;本科和硕士都是 985 院校毕业&#xff0c;并且是除了清北浙之外&#xff0c;排名非常靠前的 985院校。 本硕专业都是计算机专业&#xff0c;…

MySQL数据库-理论基础

1.1 什么是数据库 数据&#xff1a; 描述事物的符号记录&#xff0c; 可以是数字、 文字、图形、图像、声音、语言等&#xff0c;数据有多种形式&#xff0c;它们都可以经过数字化后存入计算机。 数据库&#xff1a; 存储数据的仓库&#xff0c;是长期存放在计算机内、有组织…

84 C++对象模型探索。数据语义学 - 继承多个类的时的数据布局问题。

此章节分析多继承问题&#xff0c;难点&#xff0c;但是非重点&#xff0c;实际开发中&#xff0c;多继承用的很少&#xff0c;容易被code review&#xff0c;可以不看。 我们要访问一个类对象中的成员 成员的定位是通过如下两个因素决定的&#xff1a;this指针(编译器会自动调…

向日葵企业“云策略”升级 支持Android 被控策略设置

此前&#xff0c;贝锐向日葵推出了适配PC企业客户端的云策略功能&#xff0c;这一功能支持管理平台统一修改设备设置&#xff0c;上万设备实时下发实时生效&#xff0c;很好的解决了当远程控制方案部署后&#xff0c;想要灵活调整配置需要逐台手工操作的痛点&#xff0c;大幅提…

Redis系列-数据结构篇

数据结构 string&#xff08;字符串&#xff09; redis的字符串是动态字符串&#xff0c;类似于ArrayList&#xff0c;采用预分配冗余空间的方式减少内存的频繁分配。 struct SDS<T>{ T capacity; T len; byte flags; byte[] content; } 当字符串比较短时&#xff0c…

跟着pink老师前端入门教程-day14

2.6 main 主体模块制作 HTML&#xff1a; <div class"w"><div class"main"><!-- 焦点图模块 --><div class"focus"><ul><li><img src"./images/banner_bg.png" alt""></li>…

提高 NFS Azure 文件共享性能

本文内容 适用于增加预读大小以提高读取吞吐量Nconnect另请参阅 本文介绍如何提高 NFS Azure 文件共享的性能。 适用于 展开表 文件共享类型SMBNFS标准文件共享 (GPv2)、LRS/ZRS 标准文件共享 (GPv2)、GRS/GZRS 高级文件共享 (FileStorage)、LRS/ZRS 增加预读大…

指针的深入理解(二)

这节主要复习函数指针 函数指针 函数指针的标志就是int (* ) (数据类型)&#xff0c; 是储存函数的地址的指针变量。函数名就是的首地址。我们平常使用的函数名就是函数的地址&#xff1a; 由此可以发现&#xff0c;我们可以通过函数的地址来使用函数。 那么我们就可以知道函…

什么是Vue Vue入门案例

一、什么是Vue 概念&#xff1a;Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套 构建用户界面 的 渐进式 框架 Vue2官网&#xff1a;Vue.js 1.什么是构建用户界面 基于数据渲染出用户可以看到的界面 2.什么是渐进式 所谓渐进式就是循序渐进&#xff0c;不一定非得把V…

NC开发客户端(前端)连接启动失败can‘t connect to server, please wait

效果图 解决方法 IP地址和端口要对应 1-IP地址中间启动&#xff0c;肯定是这个127.0.0.1 2-端口号&#xff0c;要对应中间件启动在控制台输出的端口 或者是在home目录-》bin-》sysConfig.bat这里面的服务器&#xff0c; 里面可以看到对应启动ip地址和端口

2023年春秋杯网络安全联赛冬季赛_做题记录

可信计算 基于挑战码的双向认证1 可信计算赛题-双向认证挑战模式.docx 使用命令进行SSH登录上去 ssh player8.147.131.156 -p 18341 # 记得加上-p参数指定端口&#xff0c;不然默认的是22端口看见word文档的提示&#xff0c;先尝试一下 直接获得了flag1 web 魔术方…

Linux:理解信号量以及内核中的三种通信方式

文章目录 共享内存的通信速度消息队列msggetmsgsndmsgrcvmsgctl 信号量semgetsemctl 内核看待ipc资源单独设计的模块ipc资源的维护 理解信号量总结 本篇主要是基于共享内存&#xff0c;延伸出对于消息队列和信号量&#xff0c;再从内核的角度去看这三个模块实现进程间通信 共享…