目录
0.问题的背景
实际上今天要被介绍的问题大家都很明白,很常见,就是我们的这个短视频,文章之类的根据我们的浏览记录去评估我们的用户的喜好,从而给我们推送相应的视频,文章,让我们更有看下去的欲望,这个就是推荐算法,这个也是现在很常用的一个手段;
我们要使用下面的这个案例去解析这个算法,介绍他的来龙去脉:
这个是用户喜欢的这个电影的名字和对应的打分情况,我们要根据这个数据去探索,给用户推荐他可能会喜欢的电影,这个就要根据和这个用户的喜好相同的用户电影进行推荐;
1.协同过滤算法
上面的这个算法的大名叫做协同过滤算法,下面的就是这个算法的一个图示:
左边的用户和右边的用户有两项内容都是共同喜欢的,这个时候他们的两个喜好相似,系统就会把这个右边的用户喜欢的第三个产品推荐给左边的用户;
上面的这个是基于用户的推荐算法,还有基于产品的推荐算法,我们后面会讲到;
2.基于问题的分析
我们根据上面的这个表:如果告诉你这个id=1的用户是我们的目标用户,显然这个时候我们没有办法很直观的看到和这个用户的喜好相似的用户是哪一位,这个时候我们就要使用到数据透视表;
3.自身的经验浅谈
其实这个数据的透视表和皮尔逊相关系数都是很常用的,因为这个前段时间的模拟赛,我们选择了2022C题进行模拟,这个里面的铅钡玻璃和高钾玻璃以及对应的这个特征,也是需要使用到数据透视表的,因为这个里面涉及到不同类型的玻璃的颜色,纹饰等等特征;
此外,国赛的题目里面经常会有这个相关性的分析,例如这个2022C题里面的第四问的化学成分之间的关联性,这个实际上就是相关性,这个是我们躲不掉的一个问题,这个使用到的知识例如皮尔逊相关系数,斯皮尔曼相关系数等等都是我们需要掌握的,今天有幸学到了皮尔逊相关系数,感觉困扰自己很长时间的问题突然有了答案,请听我细细道来;
4.今天的博客内容概览
今天会介绍这个数据透视表的制作;
以及这个皮尔逊相关系数的具体用法以及相关的求解;
5.数据透视表
为什么要使用数据透视表,这个要达到的效果是什么,开始介绍之前,首先说一下这个数据透视表想要达到的目的是下面的这个样子:
通过这个数据透视表,我们想要直观的看到每一个用户对于每一个电影的喜好情况,如果是NAN说明这个用户没有对于这个对应的电影进行评分;
下面是使用的python语言进行这个数据透视表的创建过程:
"""
如何去制作数据透视表,把这个数据透视表写入到excel文件/csv文件里面
"""
# 导入pandas模块,简称为pd
import pandas as pd
'''数据处理'''
# 读取并拼接数据集
ratings = pd.read_csv(r"E:\pythonshuju\movie\ratings.csv")
movies = pd.read_csv(r"E:\pythonshuju\movie\movies.csv")
# 对于数据集的合并
movieRatings = pd.merge(ratings, movies)
'''构建模型'''
# 1. 构建「物品-用户数据透视表」
# 使用pivot_table()函数创建数据透视表
# 设置行索引index为"电影名",列索引columns为"用户id"
# 值values为"评分",并将结果赋值给userRatings变量
userRatings = movieRatings.pivot_table(index="电影名", columns="用户id", values="评分")
# userRatings.to_excel('111.xlsx',index=False)
# userRatings.to_csv('111.csv',index=False)
# 输出查看透视表userRatings
print(userRatings)
6.皮尔逊相关系数全方位解读
当出现了这个对应的电影的分数,我们就很难直观看到这个用户的喜好的相似度;如果对于相同的电影,一个用户给5分,一个给4分,这个时候大概率这两个用户的喜好是一样的,但是如果电影有很多,这个评分的差距又很大,这个时候很难直观的看到喜好相似度,这个时候我们就必须了解一下这个皮尔逊相关系数;
6.1基本概念
皮尔逊相关系数精确定义:用于度量两个变量或者是向量之间的相关性的参数;
6.2获得离差向量
我们想要比较这个拓拓和茂茂的相关性,首先就要得到这个离差向量,我们要以这个数据量少的一方为基础,因此这个拓拓和茂茂的比较,要以这两个的公共的数据为向量,因此这个拓拓就是543,茂茂就是553(虽然这个茂茂有5个数据);
6.3皮尔逊系数的计算公式
计算公式如下,就是普通的向量的模计算公式:
6.4参考标准
6.5相关函数
这个地方使用的就是corr函数,这个函数有两个参数,第一个是系数的类型,第二个是参数个数需要满足的最小值;
6.6寻找相似用户
#pearson皮尔逊相关系数
#kendall肯德尔相关系数
#spearman斯皮尔曼相关系数
# 下面是对于corr函数的参数的说明
#默认情况下,min_periods=1。在本例中,我们将它设置为了10,表明参与计算的样本最少数据量为10个。
#也就是说,只有当两个用户共同评分的电影在10部及以上时,才计算他们之间的皮尔逊相关系数。
#若两个用户共同评分的电影在10部以下时,则不计算他们之间的皮尔逊相关系数,结果会用空值替代。
# 导入pandas模块,简称为pd
import pandas as pd
'''数据处理'''
# 读取并拼接数据集
ratings = pd.read_csv("/Users/movie/ratings.csv")
movies = pd.read_csv("/Users/movie/movies.csv")
movieRatings = pd.merge(ratings, movies)
'''构建模型'''
# 1. 构建「物品-用户数据透视表」
userRatings = movieRatings.pivot_table(index="电影名", columns="用户id", values="评分")
# 2. 计算用户间的相关系数
corrMatrix = userRatings.corr(method="pearson", min_periods=10)
# 3. 寻找相似用户
# 3.1 获取「用户1」与其他用户之间的皮尔逊相关系数
# 删除第一行的数据,因为第一行的是自己和自己的相关系数
userCorr = corrMatrix[1].drop(index=1)
# TODO 3.2 获取最大值对应的索引,并赋值给变量mostCorrUser
mostCorrUser = userCorr.idxmax()
# 输出查看mostCorrUser
print(mostCorrUser)
6.7按照要求推荐电影
我们的推荐规则是:为目标用户推荐,与他最相似用户给到评分为5分的电影。
也就是说,我们需要先获取相似用户评分过的所有电影数据,再筛选出评分为5的电影。
但这就是最后的可推荐电影了吗?
肯定不是,别忘记还需要去掉目标用户看过的电影,这样的推荐才是准确的呢~
这个过程也比较复杂,代码和相关的注释都写在下面了,小伙伴们自行学习即可;
# 导入pandas模块,简称为pd
import pandas as pd
'''数据处理'''
# 读取并拼接数据集
ratings = pd.read_csv("/Users/movie/ratings.csv")
movies = pd.read_csv("/Users/movie/movies.csv")
movieRatings = pd.merge(ratings, movies)
'''构建模型'''
# 1. 构建「物品-用户数据透视表」
userRatings = movieRatings.pivot_table(index="电影名", columns="用户id", values="评分")
# 2. 计算用户间的相关系数
corrMatrix = userRatings.corr(method="pearson", min_periods=10)
# 3. 寻找相似用户
# 3.1 获取「用户1」与其他用户之间的皮尔逊相关系数
userCorr = corrMatrix[1].drop(index=1)
# 3.2 获取最大值对应的索引,并赋值给变量mostCorrUser
mostCorrUser = userCorr.idxmax()
# 4. 筛选可推荐电影
# 4.1 获取相似用户的电影评分数据
targetMovie = userRatings[mostCorrUser]
# 4.2 获取相似用户评分为5的电影
targetMovie = targetMovie[targetMovie.values==5]
# 4.3 获取目标用户评分过的电影数据
# 这个地方是因为有很多的空行数据,表示这个用户没有进行评分,我们需要删除
# dropna函数就是删除这个空的评分所在的这一行数据
user1Ratings = userRatings[1].dropna()
# 4.4 删除目标用户看过的电影
# TODO 获取相似用户评分为5的电影名称,并赋值给targetName
targetName = targetMovie.index
# TODO 获取目标用户评分过的电影名称,并赋值给user1Name
user1Name = user1Ratings.index
# TODO 筛选「用户1」未评分过的电影名称
# 这个地方的用户1就是我们的目标用户,我们需要筛选出来他没看过的电影
movieList = targetName[~targetName.isin(user1Name)]
# TODO 获取可推荐电影的名称
movieList = movieList.values
# 输出movieList
print(movieList)