协同过滤推荐(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. jQuery (js 和 jQuery 的区别)

    js 和 jQuery 的区别  主要体现在Dom操作 (jq代表我找到的元素对象)找元素:    js:document.get...    jquery: $(选择器)设定:jq 是jquery对 ...

  2. LeetCode 671. 二叉树中第二小的节点(Second Minimum Node In a Binary Tree) 9

    671. 二叉树中第二小的节点 671. Second Minimum Node In a Binary Tree 题目描述 给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 ...

  3. jdbc连接oracle的三种方法

    jdbc连接oracle的三种方法 使用service_name,配置方式:jdbc:oracle:thin:@//<host>:<port>/<service_name ...

  4. Python类和实例调用

    self指向的是实例对象,作为第一个参数,使用时不需要传入此参数. class Student(object): #定义一个Student类, def __init__(self, name, sco ...

  5. vector 使用pair对

    pair是一种序偶结构<x,y> 如果我们希望使用pair但又不需要map对其排序,可以在vector中使用pair对 插入pair对使用make_pair<typename,typ ...

  6. Linux基本命令讲解

    前言 不多BB,直接上图 Linux命令行的组成结构 [root@oldwang ~]# [root@oldwang ~]# [root@oldwang ~]# [root@oldwang ~]# [ ...

  7. Git学习(一)——熟悉git操作流程

    本篇笔记前面都是仔细介绍使用方法,如果想跳过这些直接熟悉怎么使用,跳到最后一个知识点完整流程介绍. git 了解:特点.优点 1.git用户版和服务版整合在一起,任何机器上都安装了两个版本 2.git ...

  8. TCP--粘包拆包,netty的解决方式

    TCP基于链接的协议,并且保证有序性. 但是,每个包的长度,需要明确,否则会发生粘包现象. 以下示例为一个自定义协议的例子,其中包含了拆包的内容. 所有的类: 协议类: public class Pe ...

  9. 起始路由改成分区(Areas)的RouteConfig.cs配置方法

    public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/ ...

  10. C# async 和 await 理解

    C# async 和 await 理解 先假设如下场景: 主函数 Main,循环等待用户输入: 计算函数 Cal,耗时计算大量数据: class Test { static int Main(stri ...