协同过滤推荐(Collaborative Filtering Recommendation)主要包括基于用户的协同过滤算法与基于物品的协同过滤算法。

下面,以movielens数据集为例,分别实践这两种算法。

movielens数据集包含四列,【用户ID|电影ID|打分|时间戳】,根据用户的历史评分向用户召回电影候选集。

UserCF

基于用户的协同过滤算法主要包括两个步骤。

(1) 找到和目标用户兴趣相似的用户集合。

(2) 找到这个集合中的用户喜欢的,且目标用户没有听说过的物品推荐给目标用户

步骤(1)的关键就是计算两个用户的兴趣相似度。可以通过Jaccard(杰卡德)公式或者通过余弦相似度计算。代码中主要使用了余弦相似度:

\[W(u,v) = \frac{N(u) \bigcap N(v)} {\sqrt{|N(u)| |N(v)|}}
\]

主函数为recommend(self,userID,K,N,useIIF):

def recommend(self,userID,K,N,useIIF):
W, user_item = self._UserSimilarity(self.X, self.y, useIIF)
rank = {}
interacted_items = user_item[userID]
for v, wuv in sorted(W[userID].items(), reverse=True)[:K]:
for i in user_item[v]:
if i not in interacted_items:
rank.setdefault(i, 0)
rank[i] += wuv
return sorted(rank.items(), key=lambda d: d[1], reverse=True)[:N]

其中,userID是将要为其推荐的用户ID,\(K\)代表要考虑多少个相似用户,\(N\)代表输出多少个推荐item。

函数_UserSimilarity用于计算用户之间的相似度,通过用户物品表与物品用户表计算出两个用户观看的相同的电影数量,当设定useIIF=True时,相同的电影数量变为加\(1 / math.log(1 + len(users))\),原因是惩罚用户\(u\)和用户\(v\)共同兴趣列表中的热门物品。

然后,会挑选出\(K\)名最相似的用户,选出这些用户下的\(N\)部电影作为推荐目标。这里涉及到两个排序,一个是用户的相似度排序,一个是item与用户的权重排序。注意,这里的电影的权重是由用户相似度累加决定的。

全部代码如下所示:

import math
import pandas as pd class UserCF:
def __init__(self,X,y):
self.X,self.y = X,y def recommend(self,userID,K,N,useIIF):
"""
Args:
userID:user id
k: K users closest to the user's interest
N:the number of recommendable item
userIIF:whether or not use userIIF
Returns:
top N recommendation
rank:[(item_id1,interest1),(item_id2,interest2)...]
"""
W, user_item = self._UserSimilarity(self.X, self.y, useIIF)
rank = {}
interacted_items = user_item[userID]
for v, wuv in sorted(W[userID].items(), reverse=True)[:K]:
for i in user_item[v]:
if i not in interacted_items:
rank.setdefault(i, 0)
rank[i] += wuv
return sorted(rank.items(), key=lambda d: d[1], reverse=True)[:N] def _UserSimilarity(self,X,Y,useIIF=False):
"""
Args:
X: user id list
Y: item id list
userIIF: whether or not use userIIF
Returns:
W : user's interest correlation
user_item: a dict:{user_id1:[item1,item2,...],..user_idn:[]}
"""
# 建立倒排表
item_user=dict()
for i in range(X.count()):
user=X.iloc[i]
item=Y.iloc[i]
if item not in item_user:
item_user[item]=set()
item_user[item].add(user) user_item=dict()
for i in range(Y.count()):
user=X.iloc[i]
item=Y.iloc[i]
if user not in user_item:
user_item[user]=set()
user_item[user].add(item) C={}
N={}
# C:输出用户u与v共同的物品数目矩阵
for i,users in item_user.items():
for u in users:
N.setdefault(u,0)
N[u]+=1
C.setdefault(u,{})
for v in users:
if u==v:
continue
C[u].setdefault(v,0)
if not useIIF:
C[u][v]+=1
else:
C[u][v]+=1 / math.log(1 + len(users))# 惩罚用户u和用户v共同兴趣列表中热门物品
W=C.copy()
for u,related_users in C.items():
for v,cuv in related_users.items():
W[u][v]=cuv/math.sqrt(N[u]*N[v])
return W,user_item if __name__ == '__main__':
moviesPath = '../data/ml-1m/movies.dat'
ratingsPath = '../data/ml-1m/ratings.dat'
usersPath = '../data/ml-1m/users.dat' ratingsDF = pd.read_csv(ratingsPath, index_col=None, sep='::', header=None,names=['user_id', 'movie_id', 'rating', 'timestamp'])
X=ratingsDF['user_id'][:100000]
Y=ratingsDF['movie_id'][:100000]
rank = UserCF(X,Y).recommend(1,K=10,N=10,useIIF=True)# 输出对用户1推荐的 top10 item
print('UserCF result',rank)

ItemCF

基于物品的协同过滤(item-based collaborative filtering)算法是目前业界应用最多的算法。基于物品的协同过滤算法主要分为两步。

(1) 计算物品之间的相似度。

(2) 根据物品的相似度和用户的历史行为给用户生成推荐列表

与UserCF类似,下面也使用了余弦相似度作用item相似度的衡量。另外,也对活跃用户做了一种软性的惩罚。

全部代码如下所示:

#-*-coding:utf-8-*-
"""
author:jamest
date:20190306
ItemCF function
"""
import math
import pandas as pd class ItemCF:
def __init__(self,X,y):
self.X,self.y = X,y def recommend(self,userID,K,N,useIUF):
"""
Args:
userID:user id
k: K items closest to the user's items
N:the number of recommendable item
useIUF:whether or not use useIUF
Returns:
top N recommendation
rank:[(item_id1,interest1),(item_id2,interest2)...]
"""
W, user_item = self._ItemSimilarity(self.X, self.y, useIUF)
rank = {}
interacted_items = user_item[userID]
for i in interacted_items:
for j, wij in sorted(W[i].items(), reverse=True)[0:K]:
if j not in interacted_items:
rank.setdefault(j, 0)
rank[j] += wij
return sorted(rank.items(), key=lambda d: d[1], reverse=True)[:N] def _ItemSimilarity(self,X,Y,useIUF=False):
"""
Args:
X: user id list
Y: item id list
useIUF: whether or not use useIUF
Returns:
W : item's correlation
user_item: a dict:{user_id1:[item1,item2,...],..user_idn:[]}
"""
# 建立倒排表
user_item = dict()
for i in range(Y.count()):
user = X.iloc[i]
item = Y.iloc[i]
if user not in user_item:
user_item[user] = set()
user_item[user].add(item) C = {}
N = {}
for u, items in user_item.items():
for i in items:
N.setdefault(i, 0)
N[i] += 1
C.setdefault(i, {})
for j in items:
if i == j:
continue
C[i].setdefault(j, 0)
if not useIUF:
C[i][j] += 1
else:
C[i][j] += 1 / math.log(1 + len(items)) # 对活跃用户做了一种软性的惩罚
W = C.copy()
for i, related_items in C.items():
for j, cij in related_items.items():
W[i][j] = cij / math.sqrt(N[i] * N[j])
return W, user_item if __name__ == '__main__':
moviesPath = '../data/ml-1m/movies.dat'
ratingsPath = '../data/ml-1m/ratings.dat'
usersPath = '../data/ml-1m/users.dat' # usersDF = pd.read_csv(usersPath,index_col=None,sep='::',header=None,names=['user_id', 'gender', 'age', 'occupation', 'zip'])
# moviesDF = pd.read_csv(moviesPath,index_col=None,sep='::',header=None,names=['movie_id', 'title', 'genres'])
ratingsDF = pd.read_csv(ratingsPath, index_col=None, sep='::', header=None,names=['user_id', 'movie_id', 'rating', 'timestamp'])
X=ratingsDF['user_id'][:10000]
Y=ratingsDF['movie_id'][:10000]
rank = ItemCF(X,Y).recommend(1,K=10,N=10,useIUF=True)#输出对用户1推荐的 top10 item
print('ItemCF result',rank)

参考:

推荐系统概述(一)

Github

个性化召回算法实践(一)——CF算法的更多相关文章

  1. 个性化排序算法实践(五)——DCN算法

    wide&deep在个性化排序算法中是影响力比较大的工作了.wide部分是手动特征交叉(负责memorization),deep部分利用mlp来实现高阶特征交叉(负责generalizatio ...

  2. 个性化排序算法实践(三)——deepFM算法

    FM通过对于每一位特征的隐变量内积来提取特征组合,最后的结果也不错,虽然理论上FM可以对高阶特征组合进行建模,但实际上因为计算复杂度原因,一般都只用到了二阶特征组合.对于高阶特征组合来说,我们很自然想 ...

  3. 个性化召回算法实践(三)——PersonalRank算法

    将用户行为表示为二分图模型.假设给用户\(u\)进行个性化推荐,要计算所有节点相对于用户\(u\)的相关度,则PersonalRank从用户\(u\)对应的节点开始游走,每到一个节点都以\(1-d\) ...

  4. 个性化召回算法实践(四)——ContentBased算法

    ContentBased算法的思想非常简单:根据用户过去喜欢的物品(本文统称为 item),为用户推荐和他过去喜欢的物品相似的物品.而关键就在于这里的物品相似性的度量,这才是算法运用过程中的核心. C ...

  5. 个性化召回算法实践(二)——LFM算法

    LFM算法核心思想是通过隐含特征(latent factor)联系用户兴趣和物品,找出潜在的主题和分类.LFM(latent factor model)通过如下公式计算用户u对物品i的兴趣: \[ P ...

  6. 个性化排序算法实践(一)——FM算法

    因子分解机(Factorization Machine,简称FM)算法用于解决大规模稀疏数据下的特征组合问题.FM可以看做带特征交叉的LR. 理论部分可参考FM系列,通过将FM的二次项化简,其复杂度可 ...

  7. 个性化排序算法实践(二)——FFM算法

    场感知分解机(Field-aware Factorization Machine ,简称FFM)在FM的基础上进一步改进,在模型中引入类别的概念,即field.将同一个field的特征单独进行one- ...

  8. 算法实践--最小生成树(Kruskal算法)

    什么是最小生成树(Minimum Spanning Tree) 每两个端点之间的边都有一个权重值,最小生成树是这些边的一个子集.这些边可以将所有端点连到一起,且总的权重最小 下图所示的例子,最小生成树 ...

  9. [迷宫中的算法实践]迷宫生成算法——递归分割算法

    Recursive division method        Mazes can be created with recursive division, an algorithm which wo ...

随机推荐

  1. 【Chrome插件】右键搜--多站点搜索

    写在前面:看文章前请先看文章写作时间,避免浪费时间.2019-09-10 使用场景 一次输入,同时在多个网站进行内容搜索,比如一键在不同网站搜索电影.一键获取多个搜索引擎的搜索结果. 操作演示 评分 ...

  2. 使用派生镜像(qcow2)

    当创建的虚拟机越来越多,并且你发现好多虚拟机都是同一个操作系统,它们的区别就是安装的软件不大一样,那么你肯定会希望把他们公共的部分提取出来,只保存那些与公共部分不同的东西,这样镜像大小下去了,空间变多 ...

  3. 网页授权access_token,基础支持access_token,jsapi_ticket

    微信开发中网页授权access_token与基础支持的access_token异同 问题1:网页授权access_token与分享的jssdk中的access_token一样吗? 答:不一样.网页授权 ...

  4. SSM-CRUD

    一.项目介绍 前端技术:query+Bootstrap+ajax+json 后端技术:SSM(spring.springMVC.mybatis).JSR303校验 数据库:mysql 服务器:tomc ...

  5. (二)Spring Boot 官网文档学习之入门

    文章目录 Spring Boot 是什么 系统要求 Servlet 容器 Maven方式安装Spring Boot 编写第一个 Spring Boot 项目 原文:https://docs.sprin ...

  6. SQL语言(一)

    数据定义语言:简称DDL(Data Definition Language) create database 数据库名 character set 'utf-8'; drop database 数据库 ...

  7. SDK的使用步骤

    SDK包括三种类型文件: (1).头文件(.h) (2).库文件(.lib) (3).动态库(.dll) 第一步:在项目目录中新建一个Libs文件夹,再在该文件夹中分别新建inc文件夹和lib文件夹, ...

  8. 随记sqlserver学习笔记(一)

    create database testuse test --部门表create table department( dept_id int not null identity primary key ...

  9. AVR单片机教程——EasyElectronics Library v1.0手册

    更新:EasyElectronics Library v1.1手册 索引: bit.h delay.h pin.h tone.h pwm.h uart.h adc.h led.h rgbw.h seg ...

  10. Missing android.support.FILE_PROVIDER_PATHS meta-data 报错原因分析

    此类错误多半因为拼写错误导致.有StackOverflow上便有网友将"FILE_PROVIDER_PATHS"误写成"FILE_PROVIDE_PATHS"的 ...