基于surprise模块快速搭建旅游产品推荐系统(代码+原理)(二 )

简介: 基于surprise模块快速搭建旅游产品推荐系统(代码+原理)

完整代码

def get_similar_users_recommendations(uid, dataset=dataset,n=10):
    # 获取训练集,这里取数据集全部数据
    trainset = dataset.build_full_trainset()
    # 考虑基线评级的协同过滤算法(使用基于用户的算法)
    algo = KNNBaseline(sim_option = user_based_sim_option)
    # 拟合训练集
    algo.fit(trainset)
    # 将原始id转换为内部id
    try:
        inner_id = algo.trainset.to_inner_uid(uid)
    except:
        return algo,set()
    # 使用get_neighbors方法得到10个最相似的用户
    neighbors = algo.get_neighbors(inner_id, k=10)  # 得到相似用户的内部索引编号
    neighbors_uid = ( algo.trainset.to_raw_uid(x) for x in neighbors ) # 得到相似用户的真实编号
    recommendations = set()
    #把评分为5的产品加入推荐列表
    for user in neighbors_uid:
        if len(recommendations) > n:
            break
        item = data[(data['用户ID']==user)&(data['产品评分']==5)]["产品名称"]
        for i in item.values:
            recommendations.add(i)
    print(f'\n推荐用户的ID是"{uid}":')
#     print(recommendations)
    for i, j in enumerate(list(recommendations)):
#         print(i)
        if i >= 10:
            break
        print(j)
    return algo,recommendations
algo,recom = get_similar_users_recommendations(2019443818,dataset, 10)

image.png


为什么要推荐这些,首先是这些产品是基于用户的相似性得到的一个大的产品范围,然后我们再用surprise库进行训练得到10个推荐产品,这些产品我们是可以预测它的评分的。


预测推荐评分

for item in recom:
    algo.predict(2019443818,item,r_ui=5,verbose=True)

image.png


从上面我们得知,最好的一个推荐产品已经产生了,首先它是评分为5的产品,其次预测出的评分也是十分接近的!但是作为一个推荐系统,我们需要的是,我虽然很喜欢这个产品,但是第二次消费的时候,总不能总是推荐我上一次消费的产品吧,这样就容易让用户产生无趣感!


所以我们可以去给我们的推荐系统增加一个筛选功能,当用户进入推荐系统,可以自定义选择是否要延续第一次的消费产品,如果不需要,那么就需要将这类产品在推荐目录下去除!


image.png


这个时候,我们又发现一个产品,推荐分和本身相似用户的评分就不错的!


此外我们还可以对预测评分进行一个排序,便于用户在选择的时候,不仅可以参考名称也可以参考预测评分!


for group_label,group_df in alldata.groupby("产品分类"):
    data = group_df[["用户ID","产品名称","产品评分"]]
    reader = Reader(line_format="user item rating")
    dataset = Dataset.load_from_df(data,reader=reader)
    print(group_label.center(50,'#'))
    get_similar_users_recommendations(2019443818,dataset, 10)


image.png


增加预测分排序功能

d={}
users=[]
ranks=[]
ests=[]
items=[]
for item in recom:
    user=algo.predict(2019443818,item,r_ui=5,verbose=True).uid
    rank=algo.predict(2019443818,item,r_ui=5,verbose=True).r_ui
    items.append(item)
    est=algo.predict(2019443818,item,r_ui=5,verbose=True).est
    users.append(user)
    ranks.append(rank)
    ests.append(est)
d={"用户ID":users,"推荐产品名称":items,"产品评分":ranks,"预测分":ests}
df=pd.DataFrame(d)
df.sort_values(by=['预测分'],ascending=False)


image.png


基于surprise系统进行推荐,采用基于用户的算法计算用户相似度,寻找最相似的10个用户集群,通过他们的产品评分得到一个最佳的产品推荐数据集,利用KNN进行预测产品推荐分,然后在按照预测分进行排序,最后我们就可以按照其推荐结果选择最佳的产品进行消费了!!


可能细心的伙伴会发现,为什么没有景区的推荐,因为在原始的数据里面就没有对景区发生行为,所以就没有推荐,这就是surprise模块的特点,代码量也很少,但是就可以完成推荐系统的实现!


当然利用surprise做推荐系统比原生算法代码进行推荐的好处是,surprise有多种算法的选择,其次还可以进行优化参数来达到我们模型的最佳效果。


附加知识

surprise可使用的模型

music_data=dataset
### 使用NormalPredictor算法,基于训练集的评分矩阵来预测空白评分的。
from surprise.model_selection import cross_validate,train_test_split
algo = NormalPredictor()
perf = cross_validate(algo, music_data, measures=['RMSE', 'MAE'],verbose=True)
print(perf)
### 使用BaselineOnly
from surprise import BaselineOnly
algo = BaselineOnly()
perf = cross_validate(algo, music_data, measures=['RMSE', 'MAE'],verbose=True)
print(perf)
### 使用基础版协同过滤
from surprise import KNNBasic
algo = KNNBasic()
perf = cross_validate(algo, music_data, measures=['RMSE', 'MAE'],verbose=True)
print(perf)
### 使用均值协同过滤
from surprise import KNNWithMeans
algo = KNNWithMeans()
perf = cross_validate(algo, music_data, measures=['RMSE', 'MAE'],verbose=True)
print(perf)
### 使用协同过滤baseline
from surprise import KNNBaseline
algo = KNNBaseline()
perf = cross_validate(algo, music_data, measures=['RMSE', 'MAE'],verbose=True)
print(perf)
### 使用SVD
from surprise import SVD
algo = SVD()
perf = cross_validate(algo, music_data, measures=['RMSE', 'MAE'],verbose=True)
print(perf)
### 使用SVD++
from surprise import SVDpp
algo = SVDpp()
perf = cross_validate(algo, music_data, measures=['RMSE', 'MAE'],verbose=True)
print(perf)
### 使用NMF
from surprise import NMF
algo = NMF()
perf = cross_validate(algo, music_data, measures=['RMSE', 'MAE'],verbose=True)
print(perf)


image.png


surprise如何优化参数(网格调参)

类似于我们的机器学习,sklearn中的网格搜索(暴力搜索),寻找最佳参数!


# 度量准则:pearson距离,协同过滤:基于item
sim_options = {'name': 'pearson_baseline', 'user_based': False}

在寻找最佳参数的时候,我们需要定义最佳参数的范围应该是属于哪一个范围,其次在利用网格搜索进行最佳参数的搜索,那么涉及到你应该查询文献知识或者去官网查看最佳参数的范围!


from surprise.model_selection import GridSearchCV
# 定义好需要优选的参数网格
param_grid = {'n_epochs': np.arange(4,10,1), 'lr_all': np.arange(0.002,0.01,0.001),
              'reg_all': np.arange(0.4,0.8,0.1)}
# 使用网格搜索交叉验证
grid_search = GridSearchCV(SVD, param_grid, measures=['RMSE', 'MAE'])
# 在数据集上找到最好的参数
grid_search.fit(dataset)
# 输出调优的参数组 
# 输出最好的RMSE结果
# 输出最好的RMSE结果
print(grid_search.best_score['rmse'])
# 输出对应最好的RMSE结果的参数
print(grid_search.best_params['rmse'])
# 输出最好的MAE结果
print(grid_search.best_score['mae'])
# 输出对应最好的MAE结果的参数
print(grid_search.best_params['mae'])

image.png

基于物品的surprise案例

根据一个item取回相似度最高的item,主要是用到algo.get_neighbors()这个函数

import io
import os
from surprise import Dataset
from surprise import KNNBaseline
def read_item_names():
    """
    获取电影名到电影id 和 电影id到电影名的映射
    构建映射字典
    :return:
    """
    filename = (os.path.expanduser('~/.surprise_data/ml-100k/ml-100k/u.item'))
    rid_to_name = {}
    name_to_rid = {}
    with io.open(filename, 'r', encoding='ISO-8859-1') as f:
        for line in f:
            line = line.split('|')
            rid_to_name[line[0]] = line[1]
            name_to_rid[line[1]] = line[0]
    return rid_to_name, name_to_rid
# 首先,用算法计算相互间的相似度
data = Dataset.load_builtin('ml-100k')
# 使用协同过滤必须有这行,将我们的算法运用于整个数据集,而不进行交叉验证,构建了新的矩阵
trainset = data.build_full_trainset()
# 度量准则:pearson距离,协同过滤:基于item
sim_options = {'name': 'pearson_baseline', 'user_based': False}
algo = KNNBaseline(sim_options=sim_options)
algo.fit(trainset=trainset)
rid_to_name, name_to_rid = read_item_names()
# 拿出来Toy Story这部电影对应的item id
toy_story_raw_id = name_to_rid['Toy Story (1995)']
# 转换为内部id
toy_story_inner_id = algo.trainset.to_inner_iid(toy_story_raw_id)
# 根据内部id找到最近的10个邻居
toy_story_neighbors = algo.get_neighbors(toy_story_inner_id, k=10)
# 将10个邻居的内部id转换为item id也就是raw
toy_story_neighbors_rids = (algo.trainset.to_raw_iid(inner_id) for inner_id in toy_story_neighbors)
# 将10个邻居的item id 转为name
toy_story_neighbors_names = (rid_to_name[raw_id] for raw_id in toy_story_neighbors_rids)
# 打印结果
print('----------The 10 nearest neighbors of Toy Story---------------')
for movie in toy_story_neighbors_names:
    print(movie)


总结

在使用surprise模块进行推荐系统的实现的时候,大致的思路就是,导入数据,转换数据,选择模型,至于如何选择模型,在初期的时候我们利用多种模型进行测试,其次确定好模型之后,我们需要对参数进行调优,如何选择参数,我们需要继续网格搜索,然后确定好最佳的参数之后,需要确定我们是基于物品还是基于用户的推荐,一些相似度度量应该选择那些,最终我们通过评估模型来验证我们的数据集,然后进行推荐!


相关文章
|
8月前
|
搜索推荐 算法 前端开发
旅游管理与推荐系统Python+Django网页平台+协同过滤推荐算法
旅游管理与推荐系统Python+Django网页平台+协同过滤推荐算法
194 0
|
2月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的大湾区旅游推荐系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的大湾区旅游推荐系统附带文章和源代码设计说明文档ppt
27 4
|
2月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的大湾区旅游推荐系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的大湾区旅游推荐系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
2月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的旅游推荐系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的旅游推荐系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
2月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的新闻推荐系统附带文章和源代码
基于SpringBoot+Vue的新闻推荐系统附带文章和源代码
70 3
|
2月前
|
JavaScript Java 测试技术
微信小程序松江大学城就餐推荐系统附带文章和源代码
微信小程序松江大学城就餐推荐系统附带文章和源代码
22 1
|
2月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp微信小程序的林业产品推荐系统的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的林业产品推荐系统的详细设计和实现
|
2月前
|
JavaScript Java 测试技术
基于springboot+vue.js的旅游推荐系统附带文章和源代码设计说明文档ppt
基于springboot+vue.js的旅游推荐系统附带文章和源代码设计说明文档ppt
25 0
|
2月前
|
JavaScript Java 测试技术
基于springboot+vue.js的林业产品推荐系统附带文章和源代码设计说明文档ppt
基于springboot+vue.js的林业产品推荐系统附带文章和源代码设计说明文档ppt
18 0
|
2月前
|
机器学习/深度学习 数据采集 算法
基于Apriori关联规则的电影推荐系统(附python代码)
这是一个基于Apriori算法的电影推荐系统概览。系统通过挖掘用户评分数据来发现关联规则,例如用户观看某部电影后可能感兴趣的其他电影。算法核心是逐层生成频繁项集并设定最小支持度阈值,之后计算规则的置信度。案例中展示了数据预处理、频繁项集生成以及规则提取的过程,具体包括用户评分电影的统计分析,如1-5部电影的评分组合。最后,通过Python代码展示了Apriori算法的实现,生成推荐规则,并给出了一个简单的推荐示例。整个过程旨在提高推荐的精准度,基于用户已评分的电影推测他们可能尚未评分但可能喜欢的电影。
189 1
基于Apriori关联规则的电影推荐系统(附python代码)