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

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

相关文章

Springboot处理跨域的实现方式(附Demo)

《Springboot处理跨域的实现方式(附Demo)》:本文主要介绍Springboot处理跨域的实现方式(附Demo),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录Springboot处理跨域的方式1. 基本知识2. @CrossOrigin3. 全局跨域设置4.

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

基于SpringBoot实现文件秒传功能

《基于SpringBoot实现文件秒传功能》在开发Web应用时,文件上传是一个常见需求,然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余,此时可以使用文件秒传技术通过识别重复... 目录前言文件秒传原理代码实现1. 创建项目基础结构2. 创建上传存储代码3. 创建Result类4.

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

idea中创建新类时自动添加注释的实现

《idea中创建新类时自动添加注释的实现》在每次使用idea创建一个新类时,过了一段时间发现看不懂这个类是用来干嘛的,为了解决这个问题,我们可以设置在创建一个新类时自动添加注释,帮助我们理解这个类的用... 目录前言:详细操作:步骤一:点击上方的 文件(File),点击&nbmyHIgsp;设置(Setti

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.