社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

PyCon 2018: SVD推荐系统在Python中的实践

dwzb • 7 年前 • 854 次点击  

PyCon 2018: SVD推荐系统在Python中的实践

引言

继搜索引擎之后,推荐系统改变了用户与网站之间的交互方式,在提高用户参与度和多样化推荐产品方面有重要的应用。亚马逊有35%的利润来源于它的推荐系统,Netflix有75%的用户根据推荐系统选择电影。

推荐系统是一个非常大的话题,本文介绍一种常用的基于模型的协同过滤算法——SVD(奇异值分解),在python中的使用。

假设我们用m个用户,n个商品,每个用户对每个商品的评分可以组成一个m*n的二维矩阵。当然,这个矩阵中会有非常多的值是不知道的,可能是用户没有用过这个商品,也有可能用户使用后没有进行评分。如下图所示

图中空白位置即未知的值。接下来,我们需要做的是根据这个残缺的二维矩阵中已知的值,预测出未知的值,即预测出每一个用户对每一个商品的评分。

可以想象,当矩阵被预测值补充完整之后,矩阵的每一行即表示一个用户对所有商品的评分,可以从这些评分中提取评分最高的几个商品推荐给用户,这样我们就完成了一个推荐系统模型。

接下来,就是如何通过已知值预测未知值的问题了,这里我们采用矩阵分解的方式,如图所示

中间矩阵可以拆分为左边和上边两个矩阵的乘积,这就是奇异值分解,一个矩阵总是可以拆分成两个矩阵相乘,SVD的原理可以见这篇博客,SVD方法在推荐系统中应用的原理可以参考这篇博客,下面,我们主要来讲讲如何在python中使用。

初始化及建立模型

首先需要安装surprise库,用下面这条命令

pip install scikit-surprise

假设我们现在有这样的数据(注:load_movielens函数不是库内置的,需要拿数据文件并自己定义,详情见文末链接中的作者源码)

movielens_df: pd.DataFrame = load_movielens()
movielens_df.head(5)

        user_id	    movie_title	            rating
36649	User 742	Jerry Maguire (1996)	4
2478	User 908	Usual Suspects, The (1995)	3
82838	User 758	Real Genius (1985)	4
69729	User 393	Things to Do in Denver when You're Dead (1995)	3
36560	User 66	    Jerry Maguire (1996)	4

即用户与电影之间的评分对应关系,下面导入需要的模块

from surprise import SVD
from surprise import Dataset, Reader
from surprise.model_selection import cross_validate, train_test_split

下面开始正式建模

第一步:初始化reader,指定评分范围为1分到5分

reader = Reader(rating_scale=(1, 5))

第二步:初始化数据,传入的数据只能有3列,必须按照这样的顺序[user_id, product_id, rating]

data = Dataset.load_from_df(movielens_df, reader)

这里需要注意:data变量已经不是DataFrame类型了,而是surprise库中的一种数据类型。从上面movielens_df的结果可以看出,我们的数据不是本文最初提到的矩阵形式,所以这一步转换就会将数据转化成surprise库需要的形式,便于之后的算法求解。

第三步:拆分训练集与测试集,75%的样本作为训练集,25%的样本作为测试集

trainset, testset = train_test_split(data, test_size=.25)

这里的trainset的类型是surprise.dataset.Trainset类型,我们可以查看数据的基本信息

trainset.n_users # 943
trainset.n_items # 596

这说明我们要用于训练的样本共有943个用户,596个商品。

第四步:训练模型,指定有100个隐含特征,使用训练集进行训练

model = SVD(n_factors=100)
model.fit(trainset)

这里需要说明一下,100个隐含特征是指,原本943*596的矩阵会被拆分成943*100和100*596的两个矩阵乘积,n_factors值可以任意指定只要不超过596即可,但是设置不同的值将会拟合出不同的模型,需要选择使结果较优的值。

我们也可以查看拆分出来的两个矩阵

model.pu.shape # (943, 100)
model.qi.shape # (596, 100)

根据模型结果进行推荐

预测一个用户对一个电影的评分

指定用户和电影名即可

a_user = "User 196"
a_product = "Toy Story (1995)"
model.predict(a_user, a_product)

# Prediction(uid='User 196', iid='Toy Story (1995)', r_ui=None, est=3.93380711688207, details={'was_impossible': False})

电影之间相关性

这里我们需要写get_vector_by_movie_titlecosine_distance函数(详情见文末链接中作者源码)

之后我们就可以实现输入两个电影名称,即可获得他们之间的相关性

toy_story_vec = get_vector_by_movie_title('Toy Story (1995)', model)
wizard_of_oz_vec = get_vector_by_movie_title('Wizard of Oz, The (1939)', model)

similarity_score = cosine_distance(toy_story_vec, wizard_of_oz_vec)
similarity_score
# 0.9461284008856982

这是完全不考虑导演等电影特征计算出来的电影相似度,因为我们只使用了评分数据。

寻找与一个电影最相似的电影

首先需要实现get_top_similarities函数,获得最相似的五个电影,最后效果如下

get_top_similarities('Star Wars (1977)', model)

	vector cosine distance	movie title
0	0.000000	            Star Wars (1977)
1	0.262668	            Empire Strikes Back, The (1980)
2	0.295667	            Return of the Jedi (1983)
3	0.435423	            Raiders of the Lost Ark (1981)

参考资料

1.视频 Daniel Pyrathon - A practical guide to Singular Value Decomposition in Python - PyCon 2018

2.surprise帮助文档

3.视频配套代码


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/Y7DQ71VPeP
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/12878
 
854 次点击