您当前的位置:资讯 > >正文
天天速递!轻松使用 Surprise 评级数据构建推荐系统

时间:2023-06-02 13:55:11   来源:个人图书馆-汉无为

如果您着手开始数据科学项目,则可能有一个用于标准任务的默认库。


【资料图】

大多数人可能会:

使用Pandas进行数据操作;

使用Scikit-learn进行通用机器学习应用程序;

使用TensorFlow或PyTorch进行深度学习。

但是你会用什么来构建推荐系统呢?

这就是惊喜发挥作用的地方。

Surprise是一个开源的Python库,使开发人员可以轻松地使用明确的评级数据构建推荐系统。

在本文中,展示如何使用 Surprise 在 CC BY-SA 10.4 许可证下使用 Kaggle 上提供的 goodbooks-0k 数据集来构建书籍推荐系统。

Dataset:

/datasets/zygmunt/goodbooks-10k

安装

您可以使用以下命令使用 pip 安装惊喜。

pipinstallscikit-surprise

如果您希望使用 Anaconda 进行包管理,可以使用以下命令安装 Surprise with Anaconda。

condainstall-cconda-forgescikit-surprise

如果要直接从GitHub安装最新版本的库,则应使用以下命令(将需要Numpy和Cython)。

pipinstallnumpycythongitclonehttps://github.com/NicolasHug/surprise.gitcdsurprisepythonsetup.pyinstall

构建图书推荐系统您可以在 GitHub 上找到此实际示例的完整代码。

导入库首先,我刚刚导入了一些用于数据操作和可视化的基本库。

importnumpyasnpimportpandasaspdimportmatplotlib.pyplotasplt%matplotlibinline

读取数据集

我使用了Kaggle上提供的goodbooks-10k数据集中的两个CSV文件。

第一个包含由超过 10,000 名用户评分的 53,000 本书的评级数据。

第二个文件包含 10,000 本书中每本书的元数据(标题、作者、ISBN 等)。

ratings_data=pd.read_csv("./data/ratings.csv.zip")books_metadata=pd.read_csv("./data/books.csv.zip")ratings_data.head(10)

创建Surprise数据集

为了使用 Surprise 训练推荐系统,我们需要创建一个 Dataset 对象。惊喜数据集对象是按此顺序包含以下字段的数据集:

用户标识

商品 ID(在本例中为每本书的 ID)

相应的评级(通常在 1-5 等范围内)

fromsurpriseimportDatasetfromsurpriseimportReaderreader=Reader(rating_scale=(1,5))data=Dataset.load_from_df(ratings_data[["user_id","book_id","rating"]],reader)

训练和交叉验证简单的 SVD 模型我们可以训练和交叉验证执行 SVD(奇异值分解)的模型,以便只需几行代码即可构建推荐系统。SVD 是一种流行的矩阵分解算法,可用于推荐系统。

使用矩阵分解的推荐系统通常遵循一种模式,其中评级矩阵被分解为表示项目(在本例中为书籍)和用户的潜在因子的矩阵乘积。

将评级表示为项目和用户因素的矩阵乘积

考虑到上图,请注意评级矩阵 R 在某些地方缺少值。矩阵分解算法使用梯度下降等过程来最小化使用矩阵因子预测现有评级时的误差。

因此,像SVD这样的算法通过允许我们“填补评级矩阵中的空白”来构建推荐系统,预测每个用户将分配给数据集中每个项目的评级。

从输入矩阵 A 开始,SVD 实际上将原始矩阵分解为三个矩阵,如下式所示。

SVD 的方程

我们可以将这些新矩阵映射到评级矩阵 R 以及项目和用户因素 Q 和 P,如下所示:

将 SVD 分解映射到用户和项目因素

在我们的图书推荐系统中,SVD 算法将评级矩阵表示为分别表示图书因素和用户因素的矩阵的乘积。

当然,这是对SVD算法的非常简短的解释,没有所有的数学细节,但是如果您想对该算法进行更详细的解释,则应查看斯坦福CS 246讲义。

在下面的代码中,我使用三重交叉验证交叉验证了 SVD 模型。

fromsurpriseimportSVDfromsurprise.model_selectionimportcross_validatesvd=SVD(verbose=True,n_epochs=10)cross_validate(svd,data,measures=["RMSE","MAE"],cv=3,verbose=True)

运行上面的代码生成了以下输出。

Fold1Fold2Fold3MeanStdRMSE(testset)0.85610.85770.85510.85630.0011MAE(testset)0.67530.67640.67460.67540.0007Fittime20.2122.6223.2522.031.31Testtime3.184.684.794.220.74

在使用 build_full_trainset 方法将用于交叉验证的数据集转换为 Surprise Trainset 对象后,我们还可以使用 fit 方法在整个数据集上训练模型。

trainset=data.build_full_trainset()svd.fit(trainset)

生成评级预测

现在我们有一个经过训练的 SVD 模型,我们可以使用它来预测用户在给定用户 ID (UID) 和项目/书籍 ID (IID) 的情况下为图书分配的评级。

下面的代码演示了如何使用预测方法执行此操作。

svd.predict(uid=10,iid=100)

预测方法返回如下所示的预测,其中包含一个名为 est的字段,该字段指示此特定用户的估计图书评级。

Prediction(uid=10,iid=100,r_ui=None,est=4.051206489275292,details={"was_impossible":False})

根据上面的输出,我们可以看到该模型预测该特定用户将(大致)对对应于 IID 为 100 的书籍给予四星评级。

该模型不会直接推荐图书,但我们可以使用此评分预测实用程序来确定用户可能会喜欢的图书,这使我们能够证明向用户推荐这些图书是合理的。

生成图书推荐

使用此评级预测实用程序,我在下面定义了以下实用程序函数来生成书籍推荐。

importdifflibimportrandomdefget_book_id(book_title,metadata):"""GetsthebookIDforabooktitlebasedontheclosestmatchinthemetadatadataframe."""existing_titles=list(metadata["title"].values)closest_titles=difflib.get_close_matches(book_title,existing_titles)book_id=metadata[metadata["title"]==closest_titles[0]]["id"].values[0]returnbook_iddefget_book_info(book_id,metadata):"""Returnssomebasicinformationaboutabookgiventhebookidandthemetadatadataframe."""book_info=metadata[metadata["id"]==book_id][["id","isbn","authors","title","original_title"]]returnbook_info.to_dict(orient="records")defpredict_review(user_id,book_title,model,metadata):"""Predictsthereview(onascaleof1-5)thatauserwouldassigntoaspecificbook."""book_id=get_book_id(book_title,metadata)review_prediction=model.predict(uid=user_id,iid=book_id)returnreview_prediction.estdefgenerate_recommendation(user_id,model,metadata,thresh=4):"""Generatesabookrecommendationforauserbasedonaratingthreshold.Onlybookswithapredictedratingatorabovethethresholdwillberecommended"""book_titles=list(metadata["title"].values)random.shuffle(book_titles)forbook_titleinbook_titles:rating=predict_review(user_id,book_title,model,metadata)ifrating>=thresh:book_id=get_book_id(book_title,metadata)returnget_book_info(book_id,metadata)

So what is

generate_recommendation

函数通过循环访问随机排列的书名列表并预测每个书名的用户评分,直到找到分级等于或高于指定阈值的图书,使其有资格推荐给用户,从而为用户生成图书推荐。

在开头打乱书名,为图书推荐增加了一些随机性。

generate_recommendation(1000,svd,books_metadata)

如上所述运行函数会产生下面的输出(请注意,由于函数的随机性,您可能会得到不同的建议)。

[{"id":7034,"isbn":"1402792808","authors":"CorbanAddison","title":"AWalkAcrosstheSun","original_title":"AWalkAcrosstheSun"}]

根据上面的输出,我们可以看到该函数返回一个字典,其中包含有关推荐书籍的元数据。多次运行此功能将产生多个书籍推荐。

在用户评论一本书后,我们可以将该数据添加到评分数据中,并重新训练模型以产生更好的推荐系统。

使用 t-SNE可视化账面因子

我们可以更进一步,根据书籍因子矩阵实际可视化书籍之间的相似性,在上图中用于解释矩阵分解模型的图表中称为 Q。

这个 10,000 x 100 的矩阵每本书都有一个 100 维的向量,这维太多了,我们无法直观地可视化,但我们可以使用降维技术将每本书表示为空间中的二维点。

在下面的代码中,我使用了一种称为t-SNE(t-分布式随机邻居嵌入)的技术将每本书表示为一个二维点,并将结果存储在数据框中。

fromsklearn.manifoldimportTSNEtsne=TSNE(n_components=2,n_iter=500,verbose=3,random_state=1)books_embedding=tsne.fit_transform(svd.qi)projection=pd.DataFrame(columns=["x","y"],data=books_embedding)projection["title"]=books_metadata["original_title"]

在为每本书创建包含二维点的数据框后,我使用 Plotly 创建了一个可视化效果,每个点对应于原始数据集中的一本书。

importplotly.expressaspxfig=px.scatter(projection,x="x",y="y")fig.show()

根据上面 Plotly 代码生成的绘图,我们可以看到代表 10,000 本书的点似乎遵循二维正态分布。我们可以用以下关于数据集中书籍的理论来解释这种分布:

有些书可能在广泛的读者中普遍流行,因此对应于此散点图中心的点。

其他书籍可能属于非常特定的类型,例如吸血鬼小说、推理小说和在特定受众中流行的浪漫小说。这些书可能对应于远离情节中心的点。

为了实际查看与每个点相关的书名,我定义了一个特定的函数,用于绘制给定书名的书籍列表。

请注意,我使用数据窗格来显示本文中嵌入的可视化效果。

在下面的代码中,我添加了一个函数参数,用于将生成的绘图发布为数据窗格报表。

importdatapaneasdpdefplot_books(titles,plot_name):book_indices=[]forbookintitles:book_indices.append(get_book_id(book,books_metadata)-1)book_vector_df=projection.iloc[book_indices]fig=px.scatter(book_vector_df,x="x",y="y",text="title",)fig.show()report=dp.Report(dp.Plot(fig))#Createareportreport.publish(name=plot_name,open=True,visibility="PUBLIC")

使用下面的代码,我绘制了与数据集中前 30 本书相关的点。

books=list(books_metadata["title"][:30])plot_books(books,plot_name="books_embedding")

这种可视化使我们能够看到不同书籍之间的相似之处。当涉及到类似用户提供的评分时,彼此靠近的图书往往表现相似。

例如,我们可以看到分别来自饥饿游戏和分歧者系列的两部小说《着火》和《分歧者》在类似用户中很受欢迎。

总结

Surprise是一个易于使用的Python库,它允许我们快速构建基于评级的推荐系统,而无需重新发明轮子。

Surprise还使我们能够在使用SVD等模型时访问矩阵因子,这使我们能够可视化数据集中项目之间的相似性。

来源:

Z. Zajac,Goodbooks-10k dataset (2017)Kaggle./datasets/zygmunt/goodbooks-10k

J. Leskovec,斯坦福CS 246挖掘海量数据集讲义2015,斯坦福网络分析项目。/class/cs246-2015/handouts.html

标签:

精心推荐