基于上下文的推荐 -- 包括时间衰减算法和位置推荐算法(代码实现)

2024-05-07 13:38

本文主要是介绍基于上下文的推荐 -- 包括时间衰减算法和位置推荐算法(代码实现),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于上下文的推荐

    基于时间特征的推荐
        时间衰减
            基于时间衰减的ItemCF算法
                算法核心两部分,都加入了时间衰减项
                    以movielens数据集实现ItemCF
            基于时间衰减的UserCF算法
                    以movielens数据集实现UserCF
    基于地点和热度推荐
            原理(包含三种数据集)
            以home-less数据集为例实现代码

基于时间特征的推荐

时间信息对用户兴趣的影响:

    物品具有生命周期(例如春节档电影)
    用户兴趣随时间变化
    季节效应(冬奶茶夏圣代,吸溜)
    所以在给定时间信息后,对于推荐系统变成了一个时变的系统。

对于Delicious数据集(包括4部分–用户ID,日期,网页URL和标签)我们用不同的指标可以度量网站中物品的生命周期:

    物品评价在线天数
    相隔T天系统物品流行度向量的平均相似度(判断用户兴趣的转变)
    在这里插入图片描述
    可以看到成指数级下降,即我们推荐时要降低几天前的权重。
    实现实时性要求推荐算法:
    要求每个用户访问时,要根据用户当前时间点前的行为实时计算推荐列表。
    推荐算法要平衡考虑用户近期和长期行为(用户有长期的兴趣爱好)

对于现实中的推荐系统表现可以看出:对于推荐的书籍会在你搜索某本书籍时发生一两本的变化,但是整体还是稳定的,维持着用户长期兴趣的推荐。

通过对用户调查的实验观察得出:
在这里插入图片描述
对于没有用户行为时,实现时间多样性的方法:

    在生成结果时加入随机性
    记录用户每天看到的推荐结果,再次推荐时针对前几天看到很多次的推荐结果降权
    (若降权后,推荐的仍在列表前面则继续推荐)

时间衰减

在这里插入图片描述
基于时间衰减的ItemCF算法
算法核心两部分,都加入了时间衰减项

时间衰减函数:在这里插入图片描述
在这里插入图片描述
以movielens数据集实现ItemCF

import json
import pandas as pd
import math
import os
from operator import itemgetter
from sklearn.model_selection import train_test_split


class NewItemCF:
    def __init__(self,datafile,simfile):
        self.alpha = 0.5
        self.beta = 0.8
        #文件目录
        self.datafile = datafile
        #存放相似度矩阵的文件目录
        self.simfile=simfile
        #最大的时间
        self.max_time=self.get_maxtime()
        #获得训练集与测试集
        self.train, self.test = self.loadData()
        if os.path.exists(simfile):
            self.items_sim=json.load(open('data/items_sim.json', 'r'))
        else:
            self.items_sim = self.ItemSimilarityBest()
    def loadData(self):
        data = list()
        with open(self.datafile, 'r') as f:
            lines = f.readlines()
        for line in lines:

            userid, itemid, record, timestamp = line.split("::")
            data.append((userid, itemid, int(record), int(timestamp)))


        train_list, test_list = train_test_split(data, test_size=0.3,random_state=1)

        train_dict = self.transform(train_list)
        test_dict = self.transform(test_list)

        return train_dict, test_dict
    def get_maxtime(self):
        title = ['user', 'movie', 'rating', 'time']
        data = pd.read_csv(self.datafile, sep='::', names=title,engine = 'python')
        return data['time'].max()
    def transform(self,data):
        data_dict=dict()
        for userid,itemid,record,timestamp in data:
            data_dict.setdefault(userid,{})
            data_dict[userid].setdefault(itemid,{})
            data_dict[userid][itemid]['rate']=record
            data_dict[userid][itemid]['time']=timestamp
        return data_dict

    def ItemSimilarityBest(self):
        items_sim=dict()
        #统计每个物品的关联用户数
        item_user_count=dict()
        #两两物品相似度计算的分子部分
        C=dict()

        for user,items in self.train.items():
            for i in items.keys():
                item_user_count.setdefault(i,0)
                if self.train[user][i]['rate']>0:
                    item_user_count[i]+=1
                if i not in C.keys():
                    C[i]=dict()
                for j in items.keys():
                    if i==j:
                        continue
                    if j not in C[i].keys():
                        C[i][j]=0
                    if self.train[user][i]['rate']>0 and self.train[user][j]['rate']>0:
                        C[i][j]+=1/(1+self.alpha*abs(self.train[user][i]['time']-self.train[user][j]['time'])/(24*60*60))

        for i,related_items in C.items():
            items_sim.setdefault(i,dict())
            for j,cij in related_items.items():
                items_sim[i][j]=cij/math.sqrt(item_user_count[i]*item_user_count[j])

        json.dump(items_sim, open(self.simfile, 'w'))
        return items_sim

    def recommand(self,user,K=20,N=10):
        items_sim=self.items_sim
        rank=dict()

        ru=self.train.get(user,{})
        for i,rui in ru.items():
            for j,wij in sorted(items_sim[i].items(),key=itemgetter(1),reverse=True)[:K]:
                if j in ru.keys():
                    continue
                if j not in rank.keys():
                    rank[j]=0.0

                rank[j]+=rui['rate']*wij*(1/(1+self.beta*(self.max_time-rui['time'])/(24*60*60)))
        return sorted(rank.items(),key=itemgetter(1),reverse=True)[:N]

    def precision(self, K=20, N=10):
        hit = 0
        num=0
        for user in self.train.keys():
            tu = self.test.get(user, {})
            rank = self.recommand(user, K=K, N=N)
            for item, rate in rank:
                if item in tu:
                    hit += 1
            num += N
        precision=hit/num
        return precision

if __name__ == '__main__':
    b=NewItemCF('ml-1m/ratings.dat','data/items_sim.json')
    print(b.precision())

基于时间衰减的UserCF算法

原理同上面的ItemCF算法,这里不再解释。
以movielens数据集实现UserCF

import json
import math
import pandas as pd
import os
from operator import itemgetter
from sklearn.model_selection import train_test_split


class NewUserCF:
    def __init__(self,datafile,simfile):
        self.alpha=0.5
        self.beta=0.8
        #文件目录
        self.datafile=datafile
        #存放相似度矩阵的文件
        self.simfile=simfile
        #获取最大的时间
        self.max_time=self.get_maxtime()
        #获取数据
        self.train,self.test=self.loadData()
        #用户之间相似度
        if os.path.exists('data/users_sim.json'):
            self.users_sim=json.load(open('data/users_sim.json','r'))
        else:
            self.users_sim=self.UsersSimilarity()
    def get_maxtime(self):
        title = ['user', 'movie', 'rating', 'time']
        data = pd.read_csv(self.datafile, sep='::', names=title, engine='python')
        return data['time'].max()

    def loadData(self):
        data=list()
        with open(self.datafile,'r') as f:
            lines=f.readlines()
        for line in lines:
            userid,itemid,record,timestamp=line.split("::")
            data.append([userid,itemid,int(record),int(timestamp)])
        train_data,test_data=train_test_split(data,test_size=0.3,random_state=1)
        train_data=self.transform(train_data)
        test_data=self.transform(test_data)
        return train_data,test_data

    def transform(self,data):
        data_dict=dict()
        for userid,itemid,record,timestamp in data:
            if userid not in data_dict.keys():
                data_dict[userid]={}
            if itemid not in data_dict[userid].keys():
                data_dict[userid][itemid]={}
            data_dict[userid][itemid]['rate']=record
            data_dict[userid][itemid]['time']=timestamp
        return data_dict

    def UsersSimilarity(self):


        #物品-用户倒查表
        item_users=dict()
        for u,items in self.train.items():
            for i in items.keys():
                item_users.setdefault(i,set())
                if self.train[u][i]['rate']>0:
                    item_users[i].add(u)
        #计算两两用户相似的分子部分
        C=dict()
        #统计每个用户评价过多少个电影
        N=dict()
        for user,item_dict in self.train.items():
            if user not in N.keys():
                N[user]=0

            items=[item for item in item_dict.keys() if item_dict[item]['rate']>0]
            N[user]=len(items)
        for item,users in item_users.items():
            for u in users:
                C.setdefault(u,dict())
                for v in users:
                    C[u].setdefault(v,0.0)
                    if v==u:
                        continue
                    C[u][v]+=(1/(1+self.alpha*abs(self.train[u][item]['time']-self.train[v][item]['time'])/(24*60*60)))*(1/math.log(1+len(users)))

        users_sim=dict()
        for u,related_users in C.items():
            users_sim.setdefault(u,dict())
            for v,wuv in related_users.items():
                if u==v:
                    continue
                users_sim[u][v]=wuv/math.sqrt(N[u]*N[v])
        json.dump(users_sim,open('data/users_sim.json','w'))
        return users_sim


    def recommand(self,user,K=20,N=10):
        """

        :param user: 用户id
        :param K: 取和user相似的前K的其他用户
        :param N: 推荐N个物品
        :return: 推荐列表及用户对其的兴趣的字典
        """
        rank=dict()
        related_items=self.train.get(user,{})
        for v,wuv in sorted(self.users_sim[user].items(),key=itemgetter(1),reverse=True)[:K]:
            for i,rvi in self.train[v].items():
                if i in related_items.keys():
                    continue
                if i not in rank.keys():
                    rank[i]=0.0
                else:
                    rank[i]+=wuv*rvi['rate']*(1/(1+self.beta*(self.max_time-rvi['time'])))
        return sorted(rank.items(),key=itemgetter(1),reverse=True)[:N]
    def precision(self,K=20,N=10):
        hit=0
        num=0

        for user in self.train.keys():
            tu=self.test.get(user,{})
            rank=self.recommand(user,K=K,N=N)
            for item,rate in rank:
                if item in tu:
                    hit+=1
            num+=N
        precision=hit/num
        return precision

if __name__ == '__main__':
    a=NewUserCF('ml-1m/ratings.dat','data/users_sim.json')
    print(a.precision())


   

基于地点和热度推荐
原理(包含三种数据集)

在这里插入图片描述
以home-less数据集为例实现代码

# 这里用了老师给的代码
# 这个数据集与上面三种数据集采用的思想不一样
import pandas as pd

class RecBasedAh:
    def __init__(self,path=None,Addr='朝阳区',type='score',k=10):
        self.path=path
        self.Addr=Addr
        self.type=type
        self.k=k

        self.data=self.load_mess()
    def load_mess(self):
      # 这个函数筛选出用户位置周围的数据
        data=pd.read_csv(self.path,header=0,sep=',',encoding='GBK')
        return data[data['addr']==self.Addr]

    def recommand(self):
      # 判断推荐所依据的原因
      # else 中是综合原因 对于评分 评论条数 开业时间 装修时间分别做了加权
      # 可以自己设计自己的要求 比如对于开业时间等不做考虑
        if self.type in ['score','comment_num','lowest_price','decoration_time','open_time']:
            data=self.data.sort_values(by=[self.type,'lowest_price'],ascending=False)[:self.k]
            return dict(data.filter(items=['name',self.type]).values)
        elif self.type=='combine':
            data=self.data.filter(items=['name','score','comment_num','lowest_price','decoration_time','open_time'])
            #装修时间越近越好
            data['decoration_time']=data['decoration_time'].apply(lambda x:int(x)-2017)
            #开业时间越早越好
            data['open_time']=data['open_time'].apply(lambda x:2017-int(x))

            for col in data.keys():
                if col!='name':
                    data[col]=(data[col]-data[col].min())/(data[col].max())


            data[self.type]=1*data['score']+2*data['comment_num']+1.5*data['lowest_price']+0.5*data['decoration_time']+0.5*data['open_time']
            data=data.sort_values(by=self.type,ascending=False)[:self.k]
            return dict(data.filter(items=['name',self.type]).values)


if __name__ == '__main__':
    path='hotel-mess/hotel-mess.csv'

    hotel_rec=RecBasedAh(path,Addr='朝阳区',type='combine',k=10,sort=False)
    print(hotel_rec.recommand())

这篇关于基于上下文的推荐 -- 包括时间衰减算法和位置推荐算法(代码实现)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

mybatis执行insert返回id实现详解

《mybatis执行insert返回id实现详解》MyBatis插入操作默认返回受影响行数,需通过useGeneratedKeys+keyProperty或selectKey获取主键ID,确保主键为自... 目录 两种方式获取自增 ID:1. ​​useGeneratedKeys+keyProperty(推

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控

Linux在线解压jar包的实现方式

《Linux在线解压jar包的实现方式》:本文主要介绍Linux在线解压jar包的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux在线解压jar包解压 jar包的步骤总结Linux在线解压jar包在 Centos 中解压 jar 包可以使用 u

c++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

Qt使用QSqlDatabase连接MySQL实现增删改查功能

《Qt使用QSqlDatabase连接MySQL实现增删改查功能》这篇文章主要为大家详细介绍了Qt如何使用QSqlDatabase连接MySQL实现增删改查功能,文中的示例代码讲解详细,感兴趣的小伙伴... 目录一、创建数据表二、连接mysql数据库三、封装成一个完整的轻量级 ORM 风格类3.1 表结构

基于Python实现一个图片拆分工具

《基于Python实现一个图片拆分工具》这篇文章主要为大家详细介绍了如何基于Python实现一个图片拆分工具,可以根据需要的行数和列数进行拆分,感兴趣的小伙伴可以跟随小编一起学习一下... 简单介绍先自己选择输入的图片,默认是输出到项目文件夹中,可以自己选择其他的文件夹,选择需要拆分的行数和列数,可以通过

Python中将嵌套列表扁平化的多种实现方法

《Python中将嵌套列表扁平化的多种实现方法》在Python编程中,我们常常会遇到需要将嵌套列表(即列表中包含列表)转换为一个一维的扁平列表的需求,本文将给大家介绍了多种实现这一目标的方法,需要的朋... 目录python中将嵌套列表扁平化的方法技术背景实现步骤1. 使用嵌套列表推导式2. 使用itert

Python使用pip工具实现包自动更新的多种方法

《Python使用pip工具实现包自动更新的多种方法》本文深入探讨了使用Python的pip工具实现包自动更新的各种方法和技术,我们将从基础概念开始,逐步介绍手动更新方法、自动化脚本编写、结合CI/C... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

在Linux中改变echo输出颜色的实现方法

《在Linux中改变echo输出颜色的实现方法》在Linux系统的命令行环境下,为了使输出信息更加清晰、突出,便于用户快速识别和区分不同类型的信息,常常需要改变echo命令的输出颜色,所以本文给大家介... 目python录在linux中改变echo输出颜色的方法技术背景实现步骤使用ANSI转义码使用tpu

Knife4j+Axios+Redis前后端分离架构下的 API 管理与会话方案(最新推荐)

《Knife4j+Axios+Redis前后端分离架构下的API管理与会话方案(最新推荐)》本文主要介绍了Swagger与Knife4j的配置要点、前后端对接方法以及分布式Session实现原理,... 目录一、Swagger 与 Knife4j 的深度理解及配置要点Knife4j 配置关键要点1.Spri