建模杂谈系列239 物品协同过滤-ItemCF

2024-02-19 15:20

本文主要是介绍建模杂谈系列239 物品协同过滤-ItemCF,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

说明

推荐是很重要的一块内容,丢下有点久了。计划先快速恢复一部分基础内容,然后再和产品改进结合,丰富这块的内容。

内容

具体的理论部分可以参考这篇文章,以下从实操和我的理解做一个实践。

本质上,协同过滤是利用用户的选择,来给任意两个物品打标。

1 计算数据

以购买为例,一个用户如果购买过a,b,c,说明这三个物品存在关联。在参考文章的例子中,有5个客户,每个客户喜欢(或可认为是购买过)几种物品。

在这里插入图片描述

# 例子中的数据
data_list = ['abd','bce','cd','bcd','ad']
item_counts = dict(pd.Series(list(''.join(data_list))).value_counts()){'d': 4, 'c': 3, 'b': 3, 'a': 2, 'e': 1}

以下是两个函数

# 用户ABCDE,物品abcde
# 计算用户的C(n,2)
from itertools import combinations
import pandas as pd 
import numpy as np 
def generate_combinations_cn2(input_list):# 生成C(n, 2)的组合comb = list(combinations(input_list, 2))# 筛选不包含相同元素的组合unique_combinations = [c for c in comb if c[0] != c[1]]# 每个组合按照字母排序sorted_combinations = [tuple(sorted(c)) for c in unique_combinations]return sorted(sorted_combinations)  # 返回排序后的结果
import pandas as pd 
# 将数据框中的n列压成一列字典表示 | 用于SRule的入参构造 | 假设pandas是统一中间体
def cols2s(some_df, cols = None, cols_key_mapping = None):assert isinstance(some_df, pd.DataFrame),'some_df Must Be DataFrame'assert isinstance(cols, list), 'cols Must Be List'assert isinstance(cols_key_mapping, list), 'cols_key_mapping Must Be List'assert len(cols) == len(cols_key_mapping),'cols and cols_key_mapping Must Be Same Length'some_df_cols = list(some_df.columns)if not set(some_df_cols) >= set(cols):raise  ASetError('集合判定错误')some_df1  = some_df[cols]some_df1.columns = cols_key_mappingreturn pd.Series(some_df1.to_dict(orient='records'))
# # 示例用法
# input_list = ["b", "a", "c", "b", "d"]
# result = generate_combinations_cn2(input_list)
# print(result)
# # [('a', 'b'), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'c'), ('b', 'd'), ('b', 'd'), ('c', 'd')]

函数generate_combinations_cn2会将给定的列表进行C(n,2)组合,并将组合结果按照字母排序,这样可以用唯一的key来表达一对组合。
函数cols2s则是将一个表压缩成一个列,每个元素都是一条记录(字典)。

将每个用户的物品进行C(n,2)组合,这样可以列出一对物品出现的次数(这里也就是对共现矩阵进行一种实现)

res_list = []
for some_data in data_list:comb_res = generate_combinations_cn2(list(some_data))res_list.append(comb_res)
res_list1 = sum(res_list, [])
res_df = pd.DataFrame(res_list1)
res_df.columns = ['i','j']
res_df1 = res_df.groupby(['i','j']).size().reset_index()
res_df1.columns = ['i','j','cnt']i	j	cnt
0	a	b	1
1	a	d	2
2	b	c	2
3	b	d	2
4	b	e	1
5	c	d	2
6	c	e	1

将这个结果压缩为一列字典。

res_s = cols2s(res_df1, cols=['i','j','cnt'],cols_key_mapping=['i','j','cnt'] )
0    {'i': 'a', 'j': 'b', 'cnt': 1}
1    {'i': 'a', 'j': 'd', 'cnt': 2}
2    {'i': 'b', 'j': 'c', 'cnt': 2}
3    {'i': 'b', 'j': 'd', 'cnt': 2}
4    {'i': 'b', 'j': 'e', 'cnt': 1}
5    {'i': 'c', 'j': 'd', 'cnt': 2}
6    {'i': 'c', 'j': 'e', 'cnt': 1}
dtype: object

一对物品,除了要计算频率,还需要归一化。这点和TFIDF也很像。

def cal_weight(input_dict, item_cnt_dict = item_counts):i = input_dict['i']j = input_dict['j']cnt = input_dict['cnt']
#     print(cnt)
#     print(item_cnt_dict[i])
#     print(item_cnt_dict[j])res = cnt / np.sqrt(item_cnt_dict[i] * item_cnt_dict[j])return res
res_df1['weight'] = list(res_s.apply(cal_weight))i	j	cnt	weight
0	a	b	1	0.408248
1	a	d	2	0.707107
2	b	c	2	0.666667
3	b	d	2	0.577350
4	b	e	1	0.577350
5	c	d	2	0.577350
6	c	e	1	0.577350

2 推荐

现在假设要对用户C进行推荐,用户C购买了c和d。

# 目标客户是 C: cd
c_set = set(list('cd'))
{'c', 'd'}# 相关集合
rel_set_dict = {}
total_rel_set = set()
for some_item in sorted(list(c_set)):print(some_item)set_j = set(res_df1[res_df1['i'] ==some_item]['j'])set_i = set(res_df1[res_df1['j'] ==some_item]['i'])rel_set_dict[some_item] = set_i | set_jtotal_rel_set = total_rel_set | rel_set_dict[some_item] 其中 rel_set_dict 是和用户购买产品相关的物品集合
{'c': {'b', 'd', 'e'}, 'd': {'a', 'b', 'c'}}total_rel_set是所有相关的物品集合
{'a', 'b', 'c', 'd', 'e'}

现在要对用户没有买过的物品进行推荐

cand_set = total_rel_set - c_setcand_set是用户没有买过的
{'a', 'b', 'e'}

推荐

for cand in sorted(list(cand_set)):w = 0 for c_item in sorted(list(c_set)):if c_item <= cand:i = c_itemj = candelse:i = candj = c_item
#         print(i,j)i_sel = res_df1['i'] == ij_sel = res_df1['j'] == jij_sel = i_sel & j_selif ij_sel.sum() > 0:tem_w = res_df1[ij_sel]['weight'].iloc[0]w+= tem_wprint(cand, w)
a 0.7071067811865475
b 1.2440169358562925
e 0.5773502691896258

推荐过程如下

  • 1 遍历候选推荐物品 (cand),其对用户的总权重w初始化为0
  • 2 遍历目标用户购买的物品(c_item)
  • 3 将cand和c_item进行排序后,形成查询键,查找是否窜在关联记录(即i,j = cand, c_item)
  • 4 如果存在,那么将该权重加到w上。

通过每个cand去和用户C购买的所有物品进行查询和权重相加,获得每个cand对用户的权重,也就是推荐值。

按照TopK的方式给用户进行推荐,这样就完成了。本例中最应该推荐b。

这篇关于建模杂谈系列239 物品协同过滤-ItemCF的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/725080

相关文章

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

SpringIntegration消息路由之Router的条件路由与过滤功能

《SpringIntegration消息路由之Router的条件路由与过滤功能》本文详细介绍了Router的基础概念、条件路由实现、基于消息头的路由、动态路由与路由表、消息过滤与选择性路由以及错误处理... 目录引言一、Router基础概念二、条件路由实现三、基于消息头的路由四、动态路由与路由表五、消息过滤

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

java streamfilter list 过滤的实现

《javastreamfilterlist过滤的实现》JavaStreamAPI中的filter方法是过滤List集合中元素的一个强大工具,可以轻松地根据自定义条件筛选出符合要求的元素,本文就来... 目录1. 创建一个示例List2. 使用Stream的filter方法进行过滤3. 自定义过滤条件1. 定

Redis如何实现刷票过滤

《Redis如何实现刷票过滤》:本文主要介绍Redis如何实现刷票过滤问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录引言一、概述二、技术选型三、搭建开发环境四、使用Redis存储数据四、使用SpringBoot开发应用五、 实现同一IP每天刷票不得超过次数六

Mybatis拦截器如何实现数据权限过滤

《Mybatis拦截器如何实现数据权限过滤》本文介绍了MyBatis拦截器的使用,通过实现Interceptor接口对SQL进行处理,实现数据权限过滤功能,通过在本地线程变量中存储数据权限相关信息,并... 目录背景基础知识MyBATis 拦截器介绍代码实战总结背景现在的项目负责人去年年底离职,导致前期规

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言