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

CB的过程一般包括以下三步:

物品表示(Item Representation):为每个item抽取出一些特征(也就是item的content了)来表示此item;

特征学习(Profile Learning):利用一个用户过去喜欢(及不喜欢)的item的特征数据,来学习出此用户的喜好特征(profile);

生成推荐列表(Recommendation Generation):通过比较上一步得到的用户profile与候选item的特征,为此用户推荐一组相关性最大的item。

代码中,初始化步骤如下:

1、得到moviesDF,包括movie_id,title,genres三列;得到ratingsDF,包括user_id,movie_id,rating和timestamp。

2、得到item_cate,cate_item分别代表item中不同种类的得分(平均)以及每个种类下item得分的倒排。

3、得到self.up,形式是userid:[(category,ratio),(category1,ratio1)],代表每个用户对cate的评分。

重点有以下方法:

  • get_up(self,score_thr=4.0,topK=5)

    选出评分>score_thr的item代表用户的倾向,对时间进行加权得到time_score,具体公式为:\(time\_score=round(\frac{1}{1+(max\_ts-ts)/(24*60*60*100)},3)\),代表最近的时间点评分的item时间权重越大。根据用户对item的评分,评分的时间权重以及item下的cate权重最终得到每位用户topK的cate分数(并进行归一化)

  • recommend(self, userID, K=10)

    根据用户的cate分数得到每一个cate下top的item,作为对用户的推荐。

实际上,这里使用电影类别作为item的特征数据,来表示用户的喜好特征(profile),根据用户profile与候选item在特征下的分数,为此用户推荐一组相关性最大的item。

全部代码如下所示:

#-*-coding:utf-8-*-
"""
author:jamest
date:20190405
content based function
"""
import pandas as pd
import numpy as np
import time
import os class contentBased:
def __init__(self,rating_file,item_file):
if not os.path.exists(rating_file) or not os.path.exists(item_file):
print('the file not exists')
return
self.moviesDF = pd.read_csv(item_file, index_col=None, sep='::', header=None, names=['movie_id', 'title', 'genres'])
self.ratingsDF = pd.read_csv(rating_file, index_col=None, sep='::', header=None, names=['user_id', 'movie_id', 'rating', 'timestamp'])
self.item_cate, self.cate_item = self.get_item_cate()
self.up = self.get_up() def get_item_cate(self,topK = 10):
"""
Args:
topK:nums of items in cate_item
Returns:
item_cate:a dic,key:itemid ,value:ratio
cate_item:a dic:key:cate vale:[item1,item2,item3]
"""
movie_rating_avg = self.ratingsDF.groupby('movie_id')['rating'].agg({'item_ratings_mean': np.mean}).reset_index()
movie_rating_avg.head()
items = movie_rating_avg['movie_id'].values
scores = movie_rating_avg['item_ratings_mean'].values #得到item的平均评分
item_score_veg = {}
for item, score in zip(items, scores):
item_score_veg[item] = score #得到item中不同种类的得分
item_cate = {}
items = self.moviesDF['movie_id'].values
genres = self.moviesDF['genres'].apply(lambda x: x.split('|')).values
for item, genres_lis in zip(items, genres):
radio = 1 / len(genres_lis)
item_cate[item] = {}
for genre in genres_lis:
item_cate[item][genre] = radio recode = {}
for item in item_cate:
for genre in item_cate[item]:
if genre not in recode:
recode[genre] = {}
recode[genre][item] = item_score_veg.get(item, 0) # 不同种类item的倒排
cate_item = {}
for cate in recode:
if cate not in cate_item:
cate_item[cate] = []
for zuhe in sorted(recode[cate].items(), key=lambda x: x[1], reverse=True)[:topK]:
cate_item[cate].append(zuhe[0]) return item_cate, cate_item def get_time_score(self,timestamp,fix_time_stamp):
"""
Args:
timestamp:the timestamp of user-item
fix_time_stamp:the max timestamp of the timestamps
Returns:
a time_score:fixed range in (0,1]
"""
total_sec = 24*60*60
delta = (fix_time_stamp-timestamp)/total_sec/100
return round(1/(1+delta),3) def get_up(self,score_thr=4.0,topK=5):
"""
Args:
score_thr:select the score>=score_thr of ratingsDF
topK:the number of item in up
Returns:
a dic,key:userid ,value[(category,ratio),(category1,ratio1)]
"""
ratingsDF = self.ratingsDF[self.ratingsDF['rating'] > score_thr]
fix_time_stamp = ratingsDF['timestamp'].max()
ratingsDF['time_score'] = ratingsDF['timestamp'].apply(lambda x: self.get_time_score(x,fix_time_stamp)) users = ratingsDF['user_id'].values
items = ratingsDF['movie_id'].values
ratings = ratingsDF['rating'].values
scores = ratingsDF['time_score'].values recode = {}
up = {}
for userid, itemid, rating, time_score in zip(users, items, ratings, scores):
if userid not in recode:
recode[userid] = {} for cate in self.item_cate[itemid]:
if cate not in recode[userid]:
recode[userid][cate] = 0
recode[userid][cate] += rating * time_score * self.item_cate[itemid][cate]
for userid in recode:
if userid not in up:
up[userid] = []
total_score = 0
for zuhe in sorted(recode[userid].items(), key=lambda x: x[1], reverse=True)[:topK]:
up[userid].append((zuhe[0], zuhe[1]))
total_score += zuhe[1]
for index in range(len(up[userid])):
up[userid][index] = (up[userid][index][0], round(up[userid][index][1] / total_score, 3))
return up def recommend(self, userID, K=10):
"""
Args:
userID: the user to recom
K: the num of recom item
Returns:
a dic,key:userID ,value:recommend itemid
"""
if userID not in self.up:
return
recom_res = {}
if userID not in recom_res:
recom_res[userID] = [] for zuhe in self.up[userID]:
cate, ratio = zuhe
num = int(K * ratio) + 1
if cate not in self.cate_item:
continue
rec_list = self.cate_item[cate][:num]
recom_res[userID] += rec_list
return recom_res if __name__ == '__main__':
moviesPath = '../data/ml-1m/movies.dat'
ratingsPath = '../data/ml-1m/ratings.dat'
usersPath = '../data/ml-1m/users.dat'
recom_res = contentBased(ratingsPath,moviesPath).recommend(userID=1,K=30)
print('content based result',recom_res)

参考:

推荐系统概述(一)

Github

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

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

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

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

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

  3. 个性化召回算法实践(一)——CF算法

    协同过滤推荐(Collaborative Filtering Recommendation)主要包括基于用户的协同过滤算法与基于物品的协同过滤算法. 下面,以movielens数据集为例,分别实践这两 ...

  4. 个性化排序算法实践(四)——GBDT+LR

    本质上GBDT+LR是一种具有stacking思想的二分类器模型,所以可以用来解决二分类问题.这个方法出自于Facebook 2014年的论文 Practical Lessons from Predi ...

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. ajax页面刷新小错误(提交按钮type必须为button,而不能是submit)

    背景: 使用ajax提交form表单时,提交按钮的type值写为了submit,导致ajax中回调函数中的提示信息toastr.success('提交数据成功');没有执行,只执行了alert语句 , ...

  2. 服务发现框架选型,Consul还是Zookeeper还是etcd

    背景 本文并不介绍服务发现的基本原理.除了一致性算法之外,其他并没有太多高深的算法,网上的资料很容易让大家明白上面是服务发现. 想直接查看结论的同学,请直接跳到文末. 目前,市面上有非常多的服务发现工 ...

  3. eNSP上VLAN的基础的配置及access接口

    本实验模拟公司内部,为不同的部门划分不同的VLAN ,形成的不同广播域,来保护信息的安全,拓扑图如下所示

  4. git当前项目免密提交

    在项目目录下,执行: vim .git/config 在url后边添加用户名密码即可 ``` [core] repositoryformatversion = filemode = true bare ...

  5. [转帖]TPC-C解析系列03_TPC-C基准测试之SQL优化

    TPC-C解析系列03_TPC-C基准测试之SQL优化 http://www.itpub.net/2019/10/08/3330/ TPC-C是一个非常严苛的基准测试模型,考验的是一个完备的关系数据库 ...

  6. (二)spring Security 自定义登录页面与校验用户

    文章目录 配置 security 配置下 MVC 自定义登录页面 自定义一个登陆成功欢迎页面 效果图 小结: 使用 Spring Boot 的快速创建项目功能,勾选上本篇博客需要的功能:web,sec ...

  7. 剑指offer44:翻转单词顺序列

    1 题目描述 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上.同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思.例如,“stude ...

  8. go语言的3个包——strconv、os.Args、flag

    1. strconv包: 2. os.Args: 获取运行程序时给出的参数,可以通过os包来实现.看代码: package main import ( "fmt" "os ...

  9. git出现Invalid path

    今天换了电脑,我直接把整个仓库从电脑A复制到了电脑B,包括仓库下面的 .git 文件夹. 修改代码后我执行了一下 git add . 出现了一个报错 fatal: Invalid path 'D:/S ...

  10. Tomcat一闪而过的调试方法

    很少用tomcat来部署,都是用springboot微服务.只是以前学的时候搞demo试过而已. 软件测试的期末作业要求要测一个Javaweb的项目,给了一个包然后要求部署在tomcat中并启动. 然 ...