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. Haproxy+keepalived高可用集群实战

    1.1  Haproxy+keepalived高可用集群实战 随着互联网火热的发展,开源负载均衡器的大量的应用,企业主流软件负载均衡如LVS.Haproxy.Nginx等,各方面性能不亚于硬件负载均衡 ...

  2. nginx 配置参数详细说明

    #定义Nginx运行的用户和用户组 user www www; # #nginx进程数,建议设置为等于CPU总核心数. worker_processes 8; # #全局错误日志定义类型,[ debu ...

  3. 死锁造成oom的排错

    1.死锁的查看步骤 jps -l jstack xxxx(xxxx为java进程的进程号) ------ 2:查看java进程的参数: jps -l jinfo -flag printGcDetial ...

  4. pytorch1.0实现RNN for Regression

    import torch from torch import nn import numpy as np import matplotlib.pyplot as plt # 超参数 # Hyper P ...

  5. shell sed -i 指定内容追加.

    1.查看原文件中的内容 [root@testvm02 ~]# cat nrpe.cfg #command[check_users]=/usr/local/nagios/libexec/check_us ...

  6. Linux 实现回收站功能脚本

    #!/bin/bash function z-trash() { # 判断参数是否为空 if [ ! $1 ] then echo "z-trash error: file name of ...

  7. django使用pyecharts(2)----django加入echarts_前后台分离

    二.Django 中使用 pyecharts. 前后端分离 1.安装 djangorestframework linux pip3 install djangorestframework window ...

  8. 虚拟机VMware中安装Ubuntu18.04

    准备工作 Ubuntu 获取地址: 官网 清华镜像站 VMware 获取地址链接 安装过程 Vmware的安装过程此处不在赘述,不清楚如何安装的请自行百度,参见VMware14安装教程 然后就是Vmw ...

  9. easyExcel用于导入导出

    1.添加依赖: <!-- 现在已经更新到1.1.2-beta5 --> <dependency> <groupId>com.alibaba</groupId& ...

  10. win10下,cmd,power shell设置默认编码为‘UTF-8

    power shell 注:以下内容在非Windows平台上写的,可能会有拼写错误,如果有,请指正,我会尽快修正.可以用Powershell的配置文件(\(PROFILE)来实现.\)PROFILE默 ...