基于上下文的推荐算法

背景

之前的算法主要研究了如何联系用户和物品,将最符合用户兴趣的物品推荐给用户,但这些算法都忽略了一点,就是用户所处的上下文(context)。这些上下文包括用户访问推荐系统的时间、地点、心情等。

基于时间上下文的推荐

时间信息特性

  • 用户信息的变化的
  • 物品也有生命周期
  • 季节特性

引入时间信息后,推荐系统由静态系统变成了时变系统,用户行为变成了时间序列。

度量指标

在这里插入图片描述
时间多样性:推荐系统每天推荐结果的变化程度被定义为推荐系统的时间多样性。时间多样性高的推荐系统中用户会经常看到不同的推荐结果。

时间衰减

在这里插入图片描述
在这里插入图片描述

基于用户行为的时间衰减代码实现

基于movielens数据集
在这里插入图片描述

import pandas as pd
import numpy as np
import time

# 基于用户的协同过滤算法
class UserCF():
    def __init__(self, user_item_dict):
        # 将每个用户的物品取集合
        self.user_item_dict = user_item_dict
        # 用户列表
        self.users_list = list(self.user_item_dict.keys())

    # 惩罚热门物品和倒查表方式计算用户相似度(同倒查表方式一致,只是在相似度计算中引入惩罚))
    def computer_similer_backform_punish(self):

        import math
        item_user_dict = dict()
        # 建立物品到用户的倒查表
        for i, items in self.user_item_dict.items():
            for j in items.keys():
                if j not in item_user_dict.keys():
                    item_user_dict[j] = list()
                item_user_dict[j].append(i)

        # 建立用户矩阵
        self.user_matrix = np.zeros((len(self.users_list), len(self.users_list)))
        for item, users in item_user_dict.items():
            for user1 in users:
                for user2 in users:
                    if user1 != user2:
                        # 对热门物品进行惩罚
                        self.user_matrix[self.users_list.index(user1)][self.users_list.index(user2)] += 1 / (
                                1 + 0.00008 * abs(self.user_item_dict[user1][item] - self.user_item_dict[user2][item]))

        # 计算用户相似度
        user_similer_list = dict()
        for user1 in self.users_list:
            user_similer_list[user1] = dict()
            for user2 in self.users_list:
                if user1 != user2:
                    user_similer_list[user1][user2] = round(
                        self.user_matrix[self.users_list.index(user1)][self.users_list.index(user2)] /
                        (len(self.user_item_dict[user1]) * len(self.user_item_dict[user2])) ** 0.5, 3)
                    self.user_matrix[self.users_list.index(user1)][self.users_list.index(user2)] = \
                        user_similer_list[user1][user2]
        return user_similer_list, item_user_dict

    # 计算指定用户的推荐物品
    def compute_interest_item(self, user):

        user_similer_list, item_user_dict = self.computer_similer_backform_punish()
        # 取相似度高的前10名用户
        sort_coor = np.argsort(self.user_matrix[self.users_list.index(user)])[::-1][:10]

        recommend_item = dict()
        for item in item_user_dict.keys():
            recommend_item[item] = 0
            for i in sort_coor:
                # 推荐不在指定用户物品集中,但在相似用户物品集中的物品,r=1
                if item not in self.user_item_dict[user].keys() and item in self.user_item_dict[
                    self.users_list[i]].keys():
                    recommend_item[item] += self.user_matrix[self.users_list.index(user)][i] / (
                            1 + 0.00008 * abs(time.time() - self.user_item_dict[self.users_list[i]][item]))


        # 对推荐的物品按照感兴趣程度降序,取前10个
        #         print(recommend_item)
        recommend_item = {k: v for k, v in sorted(recommend_item.items(), key=lambda item: item[1], reverse=True)[:10] if
                          v != 0}
        return recommend_item
if __name__ == '__main__':

    with open('.././基于上下文的推荐数据集/ml-1m/ratings.dat') as f:
        data = np.array([i.strip().split('::') for i in f.readlines()])

    data = pd.DataFrame(data, columns=['user_id', 'movie_id', 'rating', 'time'])
    data = data[['user_id', 'movie_id', 'time']]
    # data = data.sample(n = 10000,replace =False,axis = 0)
    # 取前500个用户
    a = list(data.groupby('user_id'))[:100]
    user_dict = {}
    for i in a:
        user, movie = i
        user_dict[user] = {list(movie['movie_id'])[i]: int(list(movie['time'])[i]) for i in range(len(movie['movie_id']))}
    alpha = 0.8
    usercf = UserCF(user_dict)
    print('惩罚热门物品和倒查表方式计算用户相似度:')
    print(usercf.computer_similer_backform_punish()[0])
    print('推荐物品:')
    print(usercf.compute_interest_item('1'))

推荐物品:
{'858': 5.60654359595839e-07, '541': 5.415219995890854e-07, '318': 5.245715878931347e-07, '480': 5.233550660376489e-07, '1198': 5.228485695506164e-07, '1210': 5.228454709077769e-07, '1247': 5.06476667850689e-07, '2571': 5.06393423938479e-07, '2396': 5.063891826260197e-07, '2115': 5.061229882775335e-07}

import pandas as pd
import numpy as np
import time


# 基于物品的协同过滤算法
class ItemCF():
    def __init__(self, movie_dict):

        self.item_user_dict = movie_dict
        # 物品列表
        self.items_list = list(self.item_user_dict.keys())

    # 引入时间衰减和倒查表方式计算物品相似度(同倒查表方式一致,只是在相似度计算中引入惩罚))
    def computer_similer_backform_punish(self):
        # 建立物品到用户的倒查表
        user_item_dict = dict()
        for item,user in self.item_user_dict.items():
            for j in user.keys():
                if j not in user_item_dict.keys():
                    user_item_dict[j] = set()
                user_item_dict[j].add(item)
        # 建立物品二维矩阵
        self.item_matrix = np.zeros((len(self.items_list), len(self.items_list)))
        for user, items in user_item_dict.items():
            for item1 in items:
                for item2 in items:
                    if item1 != item2:
                        # 记录不同物品间共同用户的数目
                        self.item_matrix[self.items_list.index(item1)][self.items_list.index(item2)] += 1 / (
                                1 + 0.00008 * abs(self.item_user_dict[item1][user] - self.item_user_dict[item2][user]))

        # 计算物品相似度
        item_similer_list = dict()
        for item1 in self.items_list:
            item_similer_list[item1] = dict()
            for item2 in self.items_list:
                if item1 != item2:
                    # 利用二维矩阵存储的物品相似度进行计算
                    item_similer_list[item1][item2] = round(
                        self.item_matrix[self.items_list.index(item1)][self.items_list.index(item2)] /
                        (len(self.item_user_dict[item1]) * len(self.item_user_dict[item2])) ** 0.5, 3)
                    self.item_matrix[self.items_list.index(item1)][self.items_list.index(item2)] = \
                    item_similer_list[item1][item2]
        # 物品相似度归一化
        self.item_matrix = self.item_matrix / self.item_matrix.max(axis=1)

        return item_similer_list

    # 计算指定用户的推荐物品
    def compute_interest_item(self, user):
        # 物品相似度矩阵
        item_similer_list = self.computer_similer_backform_punish()
        recommend_item = dict()

        for item in self.items_list:
            recommend_item[item] = 0
            sort_coor = np.argsort(self.item_matrix[self.items_list.index(item)])[::-1][:10]
            for i in sort_coor:
                # 对不在该用户的喜欢列表,但其相似物品在该用户物品列表的物品,进行计算
                if user in self.item_user_dict[self.items_list[i]].keys() and user not in self.item_user_dict[item].keys():
                    recommend_item[item] += self.item_matrix[self.items_list.index(item)][i]/(
                                1 + 0.00008 * abs(time.time() - self.item_user_dict[self.items_list[i]][user]))

        # 对推荐的物品按照感兴趣程度降序,前10
        recommend_item = {k: v for k, v in sorted(recommend_item.items(), key=lambda item: item[1], reverse=True)[:10] if
                          v != 0}
        return recommend_item

if __name__ == '__main__':

    with open('.././基于上下文的推荐数据集/ml-1m/ratings.dat') as f:
        data = np.array([i.strip().split('::') for i in f.readlines()])

    data = pd.DataFrame(data, columns=['user_id', 'movie_id', 'rating', 'time'])
    data = data[['user_id', 'movie_id', 'time']]
    # data = data.sample(n = 10000,replace =False,axis = 0)
    # 取前100个用户
    a = list(data.groupby('movie_id'))[:100]
    movie_dict = {}
    for i in a:
        movie, user = i
        movie_dict[movie] = {list(user['user_id'])[i]: int(list(user['time'])[i]) for i in range(len(user['user_id']))}
    itemcf = ItemCF(movie_dict)

    print('惩罚活跃用户和倒查表方式计算物品相似度:')
    print(itemcf.computer_similer_backform_punish())
    print('推荐物品:')
    print(itemcf.compute_interest_item('1'))

推荐物品:
{'858': 5.606543007337043e-07, '541': 5.415219427809389e-07, '318': 5.24571532680956e-07, '480': 5.233550110807222e-07, '1198': 5.228485147045628e-07, '1210': 5.228454160598327e-07, '1247': 5.064766144577531e-07, '2571': 5.063933705698869e-07, '2396': 5.063891292550815e-07, '2115': 5.061229349580689e-07}

基于时间段图模型的推荐

算法描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

基于地点上下文的推荐

地点作为一种重要的空间特征,也是一种重要的上下文信息。不同地区的用户兴趣有所不同,用户到了不同的地方,兴趣也会有所不同。

  • 兴趣本地化:不同地方的用户兴趣存在着很大的差别。
  • 活动本地化:一个用户往往在附近的地区活动。

代码实现

只是考虑了将地点作为划分,未加入用户间作用。
基于hotel-mess数据集

import numpy as np
import pandas as pd
import random
#基于地点
def recommendHotel(data,larea):
    area_hotel_rank = dict()
    for area,info in data:
        #基于comment**(1/(1+now-decoration_time))分区域进行排序。同时考虑评论数与装修时间
        popularity_list = {info['name'].iloc[i]: (info['comment_num'].iloc[i]) ** (1 / (1+(2022 - info['decoration_time'].iloc[0]))) for i in range(len(info))}
        popularity_list = {k:v for k,v in sorted(popularity_list.items(),key=lambda a:a[1],reverse=True)}
        area_hotel_rank[area] = popularity_list

    #推荐本地区前7个,其他地区前3个
    area_list = list(area_hotel_rank.keys())
    area_list.remove(larea)

    recommend_hotel = list(area_hotel_rank[larea])[:7]
    another = [random.choice(area_list) for i in range(3)]
    for i in set(another):
        recommend_hotel+=list(area_hotel_rank[i])[:another.count(i)]
    #随机打乱
    random.shuffle(recommend_hotel)

    return  recommend_hotel

data = pd.read_csv('.././基于上下文的推荐数据集/hotel-mess/hotel-mess.csv',encoding='gbk')
data = data[['name','addr','comment_num','decoration_time']].groupby('addr')
print(recommendHotel(data,'朝阳区'))

推荐酒店
['国瑞百捷酒店(北京站崇文门店)', '速8酒店(北京四惠店)', '鑫奥宾馆(北京鸟巢店)', '国汉主题酒店(国展店)', '青年之家酒店', '高迪莱克优选酒店', '7天连锁酒店(北京西客站丽泽桥店)', '和家宾馆(安贞医院店)', '曲园快捷酒店', '99旅馆连锁(北京欢乐谷店)']

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值