基于物品的旅游产品推荐系统
摘要:近年来,旅游行业风生水起,随着社会经济的快速发展,国民消费水平不断的提高,人们将物质上的满足不断转型到精神上的需求。外出旅游成为每一个人的精神需求和物质消费倾向。2016年12月7日,国务院印发《“十三五”旅游业发展规划》,并指出要把握好时代的契机,优化旅游产业结构,创新旅游行业,保障旅游质量。
旅游行业的多元化发展和设计,不仅给相关部门带来了管理难度,也给消费者增加了选择的难度,旅游产品过多,不知道如何选择?产品质量如何?用户体验如何?大众评价又如何?这些都已经成为游客出行考虑的问题,前期做大量的旅游攻略,不仅浪费时间,而且容易造成审美疲劳,导致厌倦,最终造成消费不佳,消费动力不足,间接地影响到国民旅游的良性发展。
CF算法分为两大类,一类为基于memory的(Memory-based),另一类为基于Model的(Model-based),User-based和Item-based算法均属于Memory-based类型。推荐系统应用数据分析技术,找出用户最可能喜欢的东西推荐给用户,现在很多电子商务网站都有这个应用。目前用的比较多、比较成熟的推荐算法是协同过滤(Collaborative Filtering,简称CF)推荐算法,CF的基本思想是根据用户之前的喜好以及其他兴趣相近的用户的选择来给用户推荐物品。
User-based的基本思想是如果用户A喜欢物品a,用户B喜欢物品a、b、c,用户C喜欢a和c,那么认为用户A与用户B和C相似,因为他们都喜欢a,而喜欢a的用户同时也喜欢c,所以把c推荐给用户A。该算法用最近邻居(nearest-neighbor)算法找出一个用户的邻居集合,该集合的用户和该用户有相似的喜好,算法根据邻居的偏好对该用户进行预测。
1. 数据稀疏性。一个大型的电子商务推荐系统一般有非常多的物品,用户可能买的其中不到1%的物品,不同用户之间买的物品重叠性较低,导致算法无法找到一个用户的邻居,即偏好相似的用户。
2. 算法扩展性。最近邻居算法的计算量随着用户和物品数量的增加而增加,不适合数据量大的情况使用。
由于本研究数据量稍大,用户较多,所以本文通过基于物品的协同过滤推荐算法,针对用户进行个性化推荐和精准服务,达到游客和旅游部门之间的有效融合,对游客进行推荐服务,提高消费质量和消费趋势,加快相关部门的产业升级。
基于物品的协同过滤推荐,要找出与自己喜欢的物品相似的物品来推荐。基本思想是预先根据所有用户的历史偏好数据计算物品之间的相似性,然后把与用户喜欢的物品相类似的物品推荐给用户。例如:可以知道物品a和c非常相似,因为喜欢a的用户同时也喜欢c,而用户A喜欢a,所以把c推荐给用户A。
Item-based算法首选计算物品之间的相似度,计算相似度的方法有以下几种:
1. 基于余弦(Cosine-based)的相似度计算,通过计算两个向量之间的夹角余弦值来计算物品之间的相似性,其中分子为两个向量的内积,即两个向量相同位置的数字相乘。公式如下:
2. 基于关联(Correlation-based)的相似度计算,计算两个向量之间的Pearson-r关联度,公式如下:
3. 调整的余弦(Adjusted Cosine)相似度计算,由于基于余弦的相似度计算没有考虑不同用户的打分情况,可能有的用户偏向于给高分,而有的用户偏向于给低分,该方法通过减去用户打分的平均值消除不同用户打分习惯的影响,公式如下:
根据之前算好的物品之间的相似度,接下来对用户未打分的物品进行预测,有两种预测方法:
1. 加权求和。
用过对用户u已打分的物品的分数进行加权求和,权值为各个物品与物品i的相似度,然后对所有物品相似度的和求平均,计算得到用户u对物品i打分,公式如下:
了解过算法原理之后,我们就开始使用Python进行编写代码
需要简单易懂的项目代码请下载:
旅游消费数据集——包含用户id,用户评分、产品类别、产品名称等指标,可以作为推荐系统的数据集案例-数据集文档类资源-CSDN下载机器学习-推荐系统(基于物品).ipynb-机器学习文档类资源-CSDN下载
机器学习-推荐系统(基于用户).ipynb-机器学习文档类资源-CSDN下载
上面介绍的是基于协同过滤的推荐原理的实现方法,因为这样的实现虽然简单,但是较多繁琐,在编写Python代码的时候,由于我们知道,Python是一个神器的工具,它的优势就在于调用第三方库,那么推荐系统有没有这样的呢?答案是有!!
surprise介绍
Surprise是一个基于Python scikit构建和分析推荐系统。
Surprise(Simple Python Recommendation System Engine)是一款推荐系统库,是scikit系列中的一个。
简单易用,同时支持多种推荐算法:基础算法、基于近邻方法(协同过滤)、矩阵分解等(SVD, PMF, SVD++, NMF)
设计surprise时考虑到以下目的
让用户完美控制他们的实验。为此,特别强调文档,试图通过指出算法的每个细节尽可能清晰和准确。
减轻数据集处理的痛苦。用户可以使用内置数据集(Movielens, Jester)和他们自己的自定义数据集。
提供各种即用型预测算法, 例如:基线算法, 邻域方法,基于矩阵因子分解( SVD, PMF, SVD ++,NMF)等等。此外, 内置了各种相似性度量(余弦,MSD,皮尔逊…)。可以轻松实现新的算法思路
提供评估, 分析和比较算法性能的工具。使用强大的CV迭代器(受scikit-learn优秀工具启发)以及对一组参数的详尽搜索,可以非常轻松地运行交叉验证程序 。
常用类
项目实践
选择工具,导入相关模块
import warnings warnings.filterwarnings("ignore") from surprise import SVD,KNNBaseline,Reader,Dataset from surprise.model_selection import cross_validate,train_test_split import pandas as pd import numpy as np
导入数据(重要)
alldata = pd.read_excel("data.xlsx") data = alldata[["用户ID","产品名称","产品评分"]] reader = Reader(line_format="user item rating") dataset = Dataset.load_from_df(data,reader=reader)
这里我们将其保存为一个csv文件,因为我们只需要这几列数据,用于我们的推荐系统的实现,而在surprise模块中,读取数据就是一个需要谨慎考虑的东西。
reader = Reader(line_format='user item rating') dataset = Dataset.load_from_df(data,reader=reader)
使用surprise库下面的Reader函数进行读取,注意里面是文件的路口,由于我将其放在了当前路径下,所以只需要填写名称。
例如:
reader = Reader(line_format="user item rating", sep=',', skip_lines=1)
对于这个 Reader() 类,主要的功能是设置一个读取器。从 Reader 的使用也可以看出来,要求的输入是每行的格式,每行的分隔符,要忽略的行数。
从这个类实例时的输入上,我们可以判断出来,这个 Reader() 类的作用是构造一个读取器对象 reader,这个读取器 reader 包含了一些如何去读数据的属性。比如 reader 知道每行的数据是按照 “user item rating” 来分布的,知道每行数据由符号 "," 分割开,知道第一行的数据应该被跳过。
所以我们在构建了这个 reader 以后,就可以将它传给 Dataset() 类,来辅助我们从数据集中,按照我们想要的格式读取出来数据内容。
数据载入,由 Reader 和 Dataset 两个类来提供功能,具体的思路是由 Reader() 提供读取数据的格式,然后 Dataset 按照 Reader 的设置来完成对数据的载入。
这个时候就返回了我们surprise系统的数据格式,我们就可以按照这个开源的包进行我们的推荐了。
构建训练集
# 构建训练集 trainset = dataset.build_full_trainset()
但是这个返回的是一个surprise的:
<surprise.trainset.Trainset at 0x2b38e9098c8>
我们需要转换一下(dataframe格式),便于我们看清楚数据的样式:
pd.DataFrame(list(trainset.all_ratings()))
极大地提高了我们的编写效率和可读性!
# user-based user_based_sim_option = {'name': 'pearson_baseline', 'user_based': True} # item-based item_based_sim_option = {'name': 'pearson_baseline', 'user_based': False} ucf_model = KNNBaseline(k=10, sim_options=user_based_sim_option) icf_model = KNNBaseline(k=10, sim_options=item_based_sim_option)
模型训练和评估
cross_validate(ucf_model,dataset,cv=3,verbose=True)
注:平均绝对误差
参数说明:第一个是选用的模型(基于用户还是基于物品),数据集,几折交叉,是否展示模型评估效果。
训练模型
ucf_model.fit(trainset)
寻找相似度最高的用户集群
我们也可以使用surprise里面的KNN,寻找和你最相似的用户:
# user-based user_based_sim_option = {'name': 'pearson', 'user_based': True} # 获取训练集,这里取数据集全部数据 trainset = dataset.build_full_trainset() # 考虑基线评级的协同过滤算法 algo = KNNBaseline(sim_option = user_based_sim_option) # 拟合训练集 algo.fit(trainset) # 将原始id转换为内部id inner_id = algo.trainset.to_inner_uid(2019443818) # 使用get_neighbors方法得到10个最相似的用户 neighbors = algo.get_neighbors(inner_id, k=10) # 得到相似用户的内部索引编号 neighbors_uid = ( algo.trainset.to_raw_uid(x) for x in neighbors ) # 得到相似用户的真实编号 print(list(neighbors_uid))