协同过滤(Collaborative Filtering):UserCF and Item CF

2023-10-26

 具体的学习资料可以参考王喆老师的《深度学习推荐系统》,已经梳理好了知识体系,我也将按照这个路线再次梳理一遍,同时做一些拓展和加深理解

一、前言 

系统过滤曾是多年前推荐系统领域的应用最广泛的模型,也是基石一样的存在,重要!重要!

这里推出两篇论文,我们将简单看下论文,并进行代码复现 ,这里主要讲两部分

(1)基于用户的协同过滤算法(UserCF): 给用户推荐和他兴趣相似的其他用户喜欢的产品

(2)基于物品的协同过滤算法(ItemCF): 给用户推荐和他之前喜欢的物品相似的物品

2001年   Item-Based Collaborative Filtering Recommendation Algorithms

2003年   Amazon.com Recommendations  Item-to-Item Collaborative Filtering

二、协同过滤

1、什么是协同过滤

就是协同大家的反馈、评价和意见一起对海量的信息进行过滤,从中筛选出目标用户可能感兴趣的信息这样一个推荐过程

简而言之,我们要判断目标用户是否喜欢某物品,就是将所有用户交互的物品,生成共现矩阵(这里就是指用户对于物品的评分,存成矩阵方便后面的计算),然后通过找到相似用户(或相似物品),看相似用户的评价,进而估计出目标用户的评价

2、用户的相似度计算

计算相似度需要根据特点的不同选择不同的相似度计算方法, 比较常用的有下面几种, 

(1)余弦相似度

余弦相似度( Cosine Similarity ) 衡量 了用户向量i和用户向量J之间的向量夹角大小显然夹角越小证明余弦相似 度越大,两个用户越相似


 对于某些用户喜欢普遍低分或者普遍打高分,所以对于这种用户评分偏置的情况, 余弦相似度就不是那么好了, 可以考虑使用下面的皮尔逊相关系数。

(2)皮尔逊相关系数

相比余弦相似度,皮尔逊相关系 数通过使用用户平均分对各独立评分进行修正,减小了用户评分偏置的影响。

(3)物品平均分的方式 

基于皮尔逊系数的思路 还可以通过引入物品平均分的方式 减少物品 评分偏置对结果的影响

 3、最终的结果排序

(1)最常用的方式是利用用户相似度和相似用户的评价的加权平均获得目标用户的评价预测

(2)还有一种方式如下, 而是该物品的评分与此用户的所有评分的差值进行加权平均, 这时候考虑到了有的用户内心的评分标准不一的情况, 即有的用户喜欢打高分, 有的用户喜欢打低分的情况。

 至此, 基于用户的协同过滤算法的推荐过程完成。 

三、算法实现

1、userCF概念

基于用户相似度进行推荐,使其具备更强的社交特性, 用户能够快速得知与自己兴趣相似的人最近喜欢的是什么, 即使某个兴趣点以前不在自己的兴趣范围内, 也有可能通过 朋友 的动态快速更新自己的推荐列表

1.1 UserCF代码实现

采用的数据集是GroupLens提供的MovieLens的其中一个小数据集ml-latest-small。 该数据及包含700个用户对带有6100个标签的10000部电影的100000条评分。

(1)数据集加载

依次对应用户ID、物品ID、评分、时间戳

 划分训练集和测试集

# 声明两个字典, 分别是训练集和测试集
trainSet, testSet = {}, {}
trainSet_len, testSet_len = 0, 0
pivot = 0.75    # 训练集的比例

# 遍历data的每一行, 把userId, movidId, rating按照{user: {movidId: rating}}的方式存储, 当然定义一个随机种子进行数据集划分
for ele in data.itertuples():   # 遍历行这里推荐用itertuples, 比iterrows会高效很多
    user, movie, rating = getattr(ele, 'userId'), getattr(ele, 'movieId'), getattr(ele, 'rating')
    if random.random() < pivot:
        trainSet.setdefault(user, {})
        trainSet[user][movie] = rating
        trainSet_len += 1
    else:
        testSet.setdefault(user, {})
        testSet[user][movie] = rating 
        testSet_len += 1
例如:将用户1所交互的物品随机分3:1

Split trainingSet and testSet success!
TrainSet = 75657
TestSet = 25179

(2)计算用户间的相似度

user_sim_matrix = {}

# 构建“电影-用户”倒排索引    # key = movidID,  value=list of userIDs who have seen this move
print('Building movie-user table ...')
movie_user = {}
for user, movies in trainSet.items():   # 这里的user就是每个用户, movies还是个字典, {movieID: rating}
    for movie in movies:       # 这里的movie就是movieID了
        if movie not in movie_user:     # 如果movidID没在倒排索引里面
            movie_user[movie] = set()  # 声明这个键的值是set, 保证用户不重复
        movie_user[movie].add(user)     # 把用户加进去, 
print('Build movie-user table success!')


# 下面建立用户相似矩阵
movie_count = len(movie_user)
print('Total movie number = %d' % movie_count)

print('Build user co-rated users matrix ...')
for movie, users in movie_user.items():     # movid是movieID, users是set集合
    for u in users:           # 对于每个用户, 都得双层遍历
        for v in users:
            if u == v:
                continue
            user_sim_matrix.setdefault(u, {})      # 把字典的值设置为字典的形式
            user_sim_matrix[u].setdefault(v, 0)
            user_sim_matrix[u][v] += 1     # 这里统计两个用户对同一部电影产生行为的次数, 这个就是余弦相似度的分子
print('Build user co-rated users matrix success!')

# 下面计算用户之间的相似性
print('Calculating user similarity matrix ...')
for u, related_users in user_sim_matrix.items():
    for v, count in related_users.items():    # 这里面v是相关用户, count是共同对同一部电影打分的次数
        user_sim_matrix[u][v] = count / math.sqrt(len(trainSet[u]) * len(trainSet[v]))   # len 后面的就是用户对电影产生过行为的个数   
print('Calculate user similarity matrix success!')
Building movie-user table ...
Build movie-user table success!
Total movie number = 8765
Build user co-rated movies matrix ...
Build user co-rated movies matrix success!
Calculating user similarity matrix ...
Calculate user similarity matrix success!

(3)产生推荐

# 找到最相似的20个用户, 产生10个推荐
k = 20
n = 10

aim_user = 3      # 目标用户ID
rank ={}
watched_movies = trainSet[aim_user]      # 找出目标用户看到电影

# 下面从相似性矩阵中找到与aim_user最相近的K个用户

# v 表示相似用户, wuv表示相似程度
for v, wuv in sorted(user_sim_matrix[aim_user].items(), key=lambda x: x[1], reverse=True)[0:k]:  # 字典按值从大到小排序, 相关性高到第
    
    # 把v用户看过的电影推荐给目标用户
    for movie in trainSet[v]:
        if movie in watched_movies:
            continue
        rank.setdefault(movie, 0)
        rank[movie] += wuv
    

# 产生最后的推荐列表
rec_movies = sorted(rank.items(), key=itemgetter(1), reverse=True)[:n]  # itemgetter(1) 是简洁写法
推荐的电影

 (4)评价指标

# 准确率、召回率和覆盖率
hit = 0
rec_count = 0     # 统计推荐的影片数量, 计算查准率
test_count = 0    # 统计测试集的影片数量, 计算查全率
all_rec_movies = set()    # 统计被推荐出来的影片个数, 无重复了, 为了计算覆盖率
item_populatity = dict()   # 计算新颖度

# 先计算每部影片的流行程度
for user, items in trainSet.items():
    for item in items.keys():
        if item not in item_populatity:
            item_populatity[item] = 0
        item_populatity[item] += 1    # 这里统计训练集中每部影片用户观看的总次数, 代表每部影片的流行程度


# 计算评测指标
ret = 0
ret_cou = 0
for user, items in trainSet.items():    # 这里得保证测试集里面的用户在训练集里面才能推荐
    
    test_movies = testSet.get(user, {})
    rec_movies = recommend(user)
    for movie, w in rec_movies:
        if movie in test_movies:
            hit += 1
        all_rec_movies.add(movie)
        ret += math.log(1+item_populatity[movie])
        ret_cou += 1
    rec_count += n
    test_count += len(test_movies)
    
    
precision = hit / (1.0 * rec_count)
recall = hit / (1.0 * test_count)
coverage = len(all_rec_movies) / movie_count
ret /= ret_cou*1.0
    
print('precisioin = %.4f\nrecall = %.4f\ncoverage = %.4f\npopularity = %.4f' % (precision, recall, coverage, ret))

 

四、总结

协同过滤的头部效应较为明显、泛化能力较弱

所以后续被加以改进,提出矩阵分解在系统过滤的基础上加入隐向量的概念,加强模型处理稀疏矩阵的能力,后续将会出矩阵分解(MF)的论文及复现代码

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

协同过滤(Collaborative Filtering):UserCF and Item CF 的相关文章

  • 具有多个输入的kerasvalidation_data

    我尝试使用validation data方法 但是有问题 model fit X macd train X rsi train X ema train Y train sample weight sample weight validati
  • Cython 函数中的字符串

    我想这样做将字符串传递给 Cython 代码 test py s Bonjour myfunc s test pyx def myfunc char mystr cdef int i for i in range len mystr err
  • 如何让Python的socket服务器永远运行

    我有这段代码创建了一个简单的Python套接字服务器 但是每次客户端断开连接时它都会关闭 如何让它永远运行 import socket HOST PORT 8000 s socket socket socket AF INET socket
  • 在 Django 中获取数据库类型[重复]

    这个问题在这里已经有答案了 我需要能够确定 Django 运行时使用的数据库类型 MYSQL False if
  • 顶级棉花糖模式验证

    From 棉花糖 validation http marshmallow readthedocs org en latest quickstart html validation 我知道我可以在架构中的特定字段上注册验证器 如果验证器失败
  • 如何使 Django ManyToMany “直通”查询更加高效?

    我使用的是 ManyToManyField 和 through 类 这会在获取事物列表时产生大量查询 我想知道是否有更有效的方法 例如 这里有一些描述书籍及其几位作者的简化类 它们通过角色类 定义 编辑器 插画家 等角色 class Per
  • [python]没有属性“TessBaseAPI”

    当我编译代码时出现错误 import tessercat api tesseract TessBaseAPI 错误是 AttributeError 模块 对象没有属性 TessBaseAPI 我已经安装了tesseract via pip
  • SQLAlchemy:检查给定值是否在列表中

    问题 在 PostgreSQL 中 检查某个字段是否在给定列表中是使用IN操作员 SELECT FROM stars WHERE star type IN Nova Planet SQLAlchemy 的等价物是什么INSQL查询 我尝试过
  • 检查多维 numpy 数组的所有边是否都是零数组

    n 维数组有 2n 个边 1 维数组有 2 个端点 2 维数组有 4 个边或边 3 维数组有 6 个 2 维面 4 维数组有 8 个边 ETC 这类似于抽象 n 维立方体发生的情况 我想检查 n 维数组的所有边是否仅由零组成 以下是边由零组
  • 使用Python进行图像识别[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一个想法 就是我想识别图像中的字母 可能是 bmp或 jpg 例如 这是一个包含字母 S 的 bmp 图像 我想做的是使用Pyth
  • 什么时候用==,什么时候用is?

    奇怪的是 gt gt gt a 123 gt gt gt b 123 gt gt gt a is b True gt gt gt a 123 gt gt gt b 123 gt gt gt a is b False Seems a is b
  • 如何将一串Python代码编译成一个可以调用函数的模块?

    在 Python 中 我有一串 Python 源代码 其中包含以下函数 mySrc def foo print foo def bar print bar 我想将这个字符串编译成某种形式类似模块的对象这样我就可以调用代码中包含的函数 这是我
  • 直接打开Spyder还是通过Pythonxy打开?

    之前 我一直在运行PythonSpyder 我总是开始Spyder直接双击其图标 今天突然发现我还有一个东西叫Python x y 我注意到我也可以开始Spyder通过它 这两种方法有什么区别吗 如果不是的话 有什么意义Python x y
  • PyPI 上的轮子平台约束有什么限制吗?

    是否有任何地方 PEP 或其他地方 声明关于 Linux 轮子上传范围的限制 PyPI http pypi io 应该有 具体来说 上传是否被认为是可接受的做法linux x86 64轮子到 PyPI 而不是manylinux1 x86 6
  • 在Python中确定句子中2个单词之间的邻近度

    我需要确定 Python 句子中两个单词之间的接近度 例如 在下面的句子中 the foo and the bar is foo bar 我想确定单词之间的距离foo and bar 确定之间出现的单词数foo and bar 请注意 该词
  • django 中的“管理器”是什么?

    我已经阅读了Django官方中的定义文档 https docs djangoproject com en dev topics db managers 我仍然对什么感到困惑Manager does 文档说它们允许您操作数据库表 模型 但我仍
  • 如何使用 Ajax 在 Flask 中发布按钮值而不刷新页面?

    我有一个问题 当我单击 Flask 应用程序中的按钮时 我想避免重新加载 我知道有 Ajax 解决方案 但我想知道如何将我的按钮链接到 ajax 函数以发布按钮值并运行链接到其值的 python 函数 这是我的 html 按钮 div di
  • 使用 Python 进行 Google 搜索网页抓取 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 最近为了工作中的一些项目 学习了很多python 目前我需要使用谷歌搜索结果进行一些网络抓取 我发现几
  • 将字典写入 csv 时遇到问题,其中键作为标题,值作为列

    我有一本字典 看起来像 mydict foo 1 2 bar 3 4 asdf 5 6 我正在尝试将其写入 CSV 文件 使其看起来像 foo bar asdf 1 3 5 2 4 6 我花了最后一个小时寻找解决方案 我发现的最接近的解决方
  • 使用Python的线程模块调用ctypes函数比使用多处理更快?

    我一生都无法找出这个问题的答案 我编写了一个可以执行数百次繁重计算的脚本 我有一个绝妙的主意 将这些计算任务编写为 C 然后使用 Python 的 ctypes 与它们交互 我心想 我什至可以使用并行性进一步优化它 我最初的方法是使用线程

随机推荐

  • VUE-element-admin之配置多级路由菜单

    步骤 routers js中添加如下代码 path usermanagement alwaysShow true 是否显示父级 如果为false则只显示最内层菜单 默认false component Layout hidden false
  • NIO、AIO、BIO的区别

    一 同步阻塞I O BIO 同步阻塞I O 服务器实现模式为一个连接一个线程 即客户端有连接请求时服务器就需要启动一个线程进行处理 如果这个连接不做任何事情会造成不必要的线程开销 可以通过线程池机制来改善 BIO方式适用于连接数目比较少且固
  • Springboot配置的端口号不起作用

    在application yml文件中 进行了如下配置 server port 32088 spring profiles active dev spring application name consul client 启动项目后发现 端
  • ElasticSearch基础(一)

    ElasticSearch 适用场景 日志可视化 ELK组合 方便查询定位业务问题 存储非结构化数据 有些场景存储复杂嵌套的关系类型 使用关系型数据库联合查询将会很繁琐 并且影响性能 这时ElasticSearch是个不错的选择 全文搜索引
  • 分频电路的实现:奇数分频、偶数分频和小数分频

    目录 偶数分频 奇数分频 N 0 5分频 任意小数分频 偶数分频 偶数分频是最简单的 N分频需要计数到 N 1 并在 N 2 1 和 N 1 处更改输出的取值即可 只需要单一时钟沿计数 下面是四分频电路的实现 代码 module div4
  • 【满分】【华为OD机试真题2023B卷 JAVA&JS】数据分类

    华为OD2023 B卷 机试题库全覆盖 刷题指南点这里 数据分类 知识点位运算 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 对一个数据a进行分类 分类方法为 此数据a 四个字节大小 的四个字节相加对一个给定的值b取模 如
  • 地理信息安全在线培训考试系统题库-填空题

    第1题 依据 中华人民共和国保守国家秘密法实施条例 定密授权应当以 书面 形式作出 第2题 机关 单位对符合保密法的规定 但保密事项范围没有规定的不明确事项 应当先行拟定密级 保密期限和知悉范围 采取相应的保密措施 并自拟定之日起 10 日
  • 嵌入式 Linux 入门(六、Shell 脚本编程下:Shell 脚本语法)

    嵌入式 Linux 入门第六课 继续完成 Shell 脚本学习 本文学习 Shell 脚本语法 矜辰所致 前言 上文我们初次认识了 Shell 脚本 本文我们就要学习 Shell 脚本的语法 争取做到学完本文 你也会写 Shell 脚本 g
  • linux达芬奇安装教程,在Linux系统中能安装和运行达芬奇DaVinci Resolve 17版本

    如果你想在Linux系统中安装达芬奇DaVinci Resolve 17版本和运行它 请按以下说明操作 以下以Deepin 20 2为例 也适用在Ubuntu 20 04 UOS Debian发行版中 注意事项 其实安装达芬奇17最容易出问
  • 窈窕如烟秋水流转——同人立绘征集大赛赵婵雪·金奖

    导语 本期介绍的作品是由来自江西科技师范大学软件动漫学院的裴欣怡设计的赵婵雪形象 荣获了本次大赛赵婵雪组别的金奖 2020年12月22日 由首都版权协会联合全国部分高等院校和链游玩家及部分企业共同举办的 2020同人立绘征集大赛 正式启动
  • 为什么很多程序员 到了30来岁 就面临失业,这是真实存在的?

    前言 最近老是能在某乎上看到这样的热点问题 35 岁很多人会失业 究竟是危言耸听 还是真实存在的 为什么会有这样的情况 现在社会上有一种流行的说法 那就是在35岁左右的年龄段 许多人可能会面临失业的风险 这种说法是否夸大其词 或者确实是真实
  • ES 教程

    ES快速入门 一篇就懂 如何用Elasticsearch实现Word PDF TXT文件的全文内容检索
  • el-table 实现单元格内编辑功能

    el table 实现单元格内编辑功能 功能 双击单元格出现编辑框 编辑框失去焦点后保存内容 原理 通过v if控制编辑框与显示值显示和隐藏 通过el table 组件 的cell dblclick事件 得到row column的数据 并且
  • 使用ETL工具Kettle实现,把一个数据库中的多张表的数据同步到另外一个数据库中

    需求 使用ETL工具Kettle实现 把一个数据库中的多张表的数据 不少于3张表 同步到另外一个数据库中 1 使用Kettle工具连接MySQL数据库 连接第一个数据库db03 出现圈3说明连接成功 依次点击 转换 gt 主对象树 gt D
  • csgo服务器找不到,csgo社区服务器进不去解决方法

    近期有玩家在玩csgo的时候遇到了一些小问题 他们在询问 csgo社区服务器进不去怎么办 今天小编就带来csgo社区服务器进不去解决方法 希望对大家能有所帮助 csgo社区服务器进不去解决方法 好几个人喊进不去服务器 提示什么会话错误什么的
  • 无盘服务器秒卡 锐起0359,锐起无盘系统问题汇集

    锐起无盘系统问题汇集 锐起无盘系统问题汇集 说难也不难 上手快 但是做好难 随着大家做锐起的 时间长了 各种各样的问题都出现了 下面我说最常见的问题 无限滚动 这个很常见 有些人勾选了锐起自带的网卡pnp 导致无限滚动 这类问题最多 还有一
  • JavaWeb-实体类对象嵌套实体类对象的查询

    1 1 实体类代码 Cart类 购物车类 public class Cart 自增的购物车记录id private int cid 用户id private int uid 产品id private int pid 产品数量 private
  • C# 中的委托和事件(详解) ....

    C 中的委托和事件 委托和事件在 NET Framework 中的应用非常广泛 然而 较好地理解委托和事件对很多接触 C 时间不长的人来说并不容易 它们就像是一道槛儿 过了这个槛的人 觉得真是太容易了 而没有过去的人每次见到委托和事件就觉得
  • 编译原理题-带答案

    一 判断题 1 一个 LL l 文法一定是无二义的 Y 2 正规文法产生的语言都可以用上下文无关文法来描述 N 3 一张转换图只包含有限个状态 其中有一个被认为是初态 最多只有一个终态 Y 4 目标代码生成时 应考虑如何充分利用计算机的寄存
  • 协同过滤(Collaborative Filtering):UserCF and Item CF

    具体的学习资料可以参考王喆老师的 深度学习推荐系统 已经梳理好了知识体系 我也将按照这个路线再次梳理一遍 同时做一些拓展和加深理解 一 前言 系统过滤曾是多年前推荐系统领域的应用最广泛的模型 也是基石一样的存在 重要 重要 这里推出两篇论文