协同滤波模型的推荐算法(ACM暑校-案例学习)

2023-12-02 11:18

本文主要是介绍协同滤波模型的推荐算法(ACM暑校-案例学习),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于协同滤波的推荐技术可以细分为基于用户的协同过滤方法、基于产品的协同过滤方法、基于模型的协同过滤方法;本博文进行了一一测试。

1. 数据准备、评价指标

由于协同滤波模型需要用到用户的行为,这里选用MovieLen数据集进行测试研究。

MovieLen是明尼苏达大学计算机科学系GroupLens研究中心开发和维护的,也是最常用于测试协同滤波算法性能的公开数据集之一。Movielens提供了大量电影的用户评分。完整的版本包括超过了26000000的电影评分,他们来源于270000用户观看45000部电影的体会。GroupLens网站上提供的数据集不再提供用户人口统计信息。因此,这里使用Prajit-Datta在kaggle上提供的部分数据集。

  • 数据下载

下载地址:https://www.kaggle.com/prajitdatta/movielens-100k-dataset/data 

该数据集包括:1682部电影上943名用户的100000个评分(1-5)。每个用户至少为20部电影打分。该数据集也为用户提供简单的人口统计信息(年龄、性别、工作等)。这些数据是在1997年9月19日至1998年4月22日的七个月期间通过Movielens网站(movielens.umn.edu)收集的。此数据已被清除-从该数据集中删除了评分低于20或没有完整人口统计信息的用户。

  • 数据浏览

在解压文件中,只需要使用u.date/ u.user/ u.item三个文件。

① 查看用户图谱文件

import pandas as pd# load the u.user file into a dataframe
u_cols = ['user_id', 'age', 'sex', 'occupation', 'zip_code']
users = pd.read_csv('C:/Users/Administrator/Desktop/RecoSys/data/movielens/u.user', sep='|',names=u_cols, encoding='latin-1')
users.head()

可以看到,u.user文件中主要包含的用户图谱,如年龄,性别,职业,zip_code。

② 查看电影描述文件

i_cols = ['movie_id', 'title', 'release date', 'video release date', 'IMDB URL', 'unknow', 'Action', 'Adventure', 'Animation', 'Children\'s', 'Comedy', 'Crime', 'Documentary', 'Drama', 'Fantasy', 'Film-Noir', 'Horror', 'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Thriller', 'War','Western']
movies = pd.read_csv('C:/Users/Administrator/Desktop/RecoSys/data/movielens/u.item',sep='|', names=i_cols, encoding='latin-1')
movies.head()

可以看出,u.item文件中主要提供了电影的名字、发行时间、IMDB URL和题材等信息。因为,本编博客主要研究的是协同滤波算法,因此,电影中的题材等是用不到的,只需要保留movie_id和title就好。

movies = movies[['movie_id', 'title']]
movies.head()

③ 查看用户对电影评分文件

r_cols = ['user_id', 'movie_id', 'rating', 'timestamp']
ratings = pd.read_csv('C:/Users/Administrator/Desktop/RecoSys/data/movielens/u.data',sep='\t', names=r_cols, encoding='latin-1')
ratings.head()

  • 训练数据 training data & 测试数据 test data

DataFrame包含从1-5的用户对电影的评分。因此,可以将该问题建模为监督学习的实例,目的在于预测给定用户和电影的评分。虽然电影的分数只是1-5的五个离散值,其实质仍为回归问题。考虑用户对电影的真实评分是5:分类模型不能区分预测评分为1和4的情况。分类模型会将1-4的评分都视为错误分类。然而,回归模型却不是这样子,其对rating=4的惩罚远远大于rating=1的情况。

对于监督模型的学习,重要的一步在于训练集和测试集的划分。在本次试验中,用户评分数据中的75%用作模型训练,25%用于模型测试

from sklearn.model_selection import train_test_split
X = ratings.copy()
y = ratings['user_id']
# split into training and test datasets, stratified along user_id
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, stratify=y, random_state=42)>>> 
X_train.shape = (75000, 3)
X_test.shape = (25000, 3)
  • 评估方法

这里选用根均方差(RMSE=root-mean-square-error)对模型的推荐性能进行评估。其Python实现如下所示:

from sklearn.metrics import mean_squared_error
from numpy as npdef rmse(y_true, y_pred):return np.sqrt( mean_squared_error(y_true, y_pred) )# Function to compute the RMSE score obtained on the testing set by a model
def score(cf_model):# Construct a list of user-movie tuples from the testing datasetid_pairs = zip(X_test['user_id'], X_test['movie_id'])# Predict the rating for every user-movie tupley_pred = np.array([cf_model(user, movie) for (user, movie) in id_pairs])# Extract the actual ratings given by the users in the test datay_true = np.array(X_test['rating'])# Return the final RMSE scorereturn rmse(y_true, y_pred)

2. 基于用户的协同过滤推荐算法实例 Users-based

基于用户的协同推荐算法把主要的研究精力放在用户角度,实质上就是具有相同兴趣的用户群体进行聚类,然后对相同类群的用户进行产品推荐。核心在于对高度稀疏的用户-产品矩阵进行预测和填充。PANDAS提供了一个非常好用的函数pivot_table去构造rating矩阵:

# Build the ratings matrix using pivot_table function
r_matrix = X_train.pivot_table(values='rating', index='user_id', columns='movie_id')
r_matrix.head(5)

该矩阵就是推荐领域最最重要的了:①用户-产品矩阵是高度稀疏的;②实际应用过程中,从用户和产品两个维度考虑,评分矩阵是非常非常巨大的。

  • 均值Mean角度初步考虑

首先可以构建一个最简单的协同过滤算法,只需输入用户ID和电影ID,并输出所有看过的用户对该电影的平均评分。用户之间没有区别。换言之,每个用户的评分被赋予相等的权重。其中,有一种完全可能异常情况:有些电影只能在测试数据集进行访问,而在训练数据集不存在。该情况下,我们直接设置一个baseline,将其默认赋值为3.0。

# User Based Collaborative Filter using MEan Rating
def cf_user_mean(user_id, movie_id):# Check if movie_id exists in r_matrixif movie_id in r_matrix:# Compute the mean of all the ratings given to the moviemean_rating = r_matrix[movie_id].mean()else:# Default to a rating of 3.0 in the absence of any informationmean_rating = 3.0return mean_rating# Compute RMSE for the Mean model
score(cf_user_mean)>>> 1.0234701463131335

该方法仅仅适合讨论研究,是没有实际应用价值的:一方面,用户对产品的评分肯定会有偏好;另一方面,大部分少数群体的兴趣没有被认真关注。一种合适的改进方法是采用加权平均weighted mean。

  • 加权均值weighted mean角度考虑

在前面的模型中,我们为每一个用户分配了等同的权重。然而,与普通用户相比,对那些评分与所讨论问题相似的用户给予更多的关注。因此,在前面的模型中,比较合适的方案是为每一个用户分配一个合适的权重系数。数学可以表示为:

其中,r(u,m)表示为用户u对电影m的评分。对于相似度测量,同样采用余弦距离。

数据处理:将rating表中的NAN替换成0,然后用scikit-learn中的cosine_similarity函数进行处理。

r_matrix_dummy = r_matrix.copy().fillna(0)
r_matrix_dummy.head()
r_matrix_dummy.shape>>> (943, 1647)

from sklearn.metrics.pairwise import cosine_similarity
cosine_sim = cosine_similarity(r_matrix_dummy, r_matrix_dummy)
cosine_sim.shape>>> (943, 943)
# Convert into pandas dataframe
cosine_sim = pd.DataFrame(cosine_sim, index=r_matrix.index, columns=r_matrix.index)
cosine_sim.head()

# User Based Collabrative Filter using Weighted Mean Ratings
def cf_user_wmean(user_id, movie_id):# Check if movie_id exists in r_matrixif movie_id in r_matrix:sim_scores = cosine_sim[user_id]m_ratings = r_matrix[movie_id]idx = m_ratings[m_ratings.isnull()].indexm_ratings = m_ratings.dropna()sim_scores = sim_scores.drop(idx)wmean_rating = np.dot(sim_scores, m_ratings)/ sim_scores.sum()else:#Default to a rating of 3.0 in the absence of any informationwmean_rating = 3.0return wmean_ratingscore(cf_user_wmean)>>> 1.0174483808407588
  • 用户图谱demographics角度考虑

这是一种相对而言更加精细的处理方式。该算法的核心思想是,具有相同图谱的用户倾向于有相似的品味。因此,其有效性取决于这样的假设:女性、青少年或来自同一地区的人在电影选择时会有相同的品味。与前面的模型不同,该种算法不考虑用户对特定电影的评分。相反,算法只关注那些符合特定人群的用户。

3. 基于产品的协同过滤推荐算法实例 Items-based

Items-based和User-based方法本质是一致的,就相当于将第二节中的User变成Item。在基于产品的协同过滤中,我们计算库存中产品的成对相似性。然后,根据user_id和movie_id,计算用户对其所有评分产品的加权平均值。这个模型背后的基本思想是:一个特定的用户可能会对相似的两个产品有相似的评分。

4. 基于模型的方法 Model-based

到目前为止,上面的协同过滤算法被称为memory-based的过滤。因为他们只利用相似性度量来得出结果,并没有从数据中学习任何参数,或者为数据分配类/集群。并没有用到机械学习算法的威力。

  • 以聚类为核心的协同过滤算法 - Clustering

weighted mean-based 的滤波算法,考虑到了每一位用户的评分,最后进行加权;相反,demographic-based滤波算法仅仅考虑了‘某个圈子’的用户,最后进行平均。通常来说,weighted mean-based取得的结果会好于demographic-based,因为考虑的相对来说更广一点。但是,这两种方法仅仅用到了最直接、最粗浅的信息,一种解决方案是进行多维度用户刻画,进行利用机器学习算法解决高纬度数据处理问题。简单说,精准的推荐结果不一定唯一依赖考虑所有用户的感受!

demographic-based算法的缺点来源于他的假设:来自某个相同图谱的用户具有相同的想法和评分。这种极端的思考模式造成了算法的粗浅。Clustering-based方法,如k-means, 就是为了改善这种情况:将用户分组到一个群集中,然后在预测评分时只考虑来自同一个群集中的用户。下面以KNN-based clustering为例,构建相关的协同过滤算法。步骤如下 ①找出与用户u对电影m评分最相似的k个最近邻;②输出k个用户对电影m评分的平均值。

可以直接采用Python中的surprise(Simple Python Recommandation System Engine)库实现。Windows 平台下下载方式为:pip install scikit-surprise.

# Import the required classes and methods from the surprise library
from surprise import Reader, Dataset, KNNBasic, evaluate
# Define a Reader object - The Reader object helps in parsing the file or dataframe containing ratings
reader = Reader()
# Create the dataset to be used for building the filter
data = Dataset.load_from_df(ratings, reader)
# Define the algorithm object
knn = KNNBasic()
# Evaluate the performance in terms of RMSE
evaluate(knn, data, measures=['RMSE'])

从输出结果中,我们能够看出来。surprise库将所有的评分数据划分为5个文件包,其中4个文件包用于算法训练,第5个文件包用于模型测试。这样的过程重复了5次。

  • 监督学习和降维方法

对于mxn大小的评分矩阵,每一行代表m个用户中的一个对所有电影的评分;每一列代表n个电影中的一个接受所有用户的评分。前面已经看到了,该评分矩阵是非常稀疏的。通过监督学习的方法,我们可以尝试将这个高度稀疏的矩阵补全。

最简单的思考是,我们可以利用mx(n-1)的评分矩阵进行模型的监督训练,然后对m*1的未知评分进行预测。如此重复n次,那么评分矩阵将有可能完全被填充。理想是丰满的,现实的骨感的。因为,一开始我们用的mx(n-1)的模型训练矩阵就是高度稀疏的~~~(目前也没办法解决这个事,工程上的一种处理手段是用所属的列的均值或中值来填充缺失值,但是考虑到rating矩阵高达90%的系数,计算的均值和中位数一定会引进很大的偏差;同时降维技术,PCA/SVD也不能处理如此稀疏的情况

可以借鉴的一种思路是,Simon Funk在处理Netflix Problem时,将mx(n-1)的模型训练矩阵压缩到了更低的维度mxd (d << n),这种处理方式称为SVD-like,其实效果也比较一般。

  • 火极一时的推荐算法-奇异值分解 Singular-value decomposition

本质上,奇异值分解是一种矩阵因子技术,其输入为大型矩阵A,输出为小矩阵U和V。其中,Σ为对角矩阵用于吃调整数据的尺度。对于U矩阵,其实质表征的是用户主成分,英文专有名词对应user-embedding矩阵;V矩阵,其实质表征的是产品主成分,英文专有名词对应item-embedding矩阵。

和大多数机器学习算法一样,传统的SVD矩阵对极其稀疏的评分矩阵是没有效益的。然而,SimonFunk找到了解决这个问题的方法,他的解决方案(SVD++)促成了了推荐系统领域最著名的算法之一。该方法可以利用高度稀疏的评分矩阵A,生成两个非常稠密的user-embedding矩阵U和item-embedding矩阵V。这些稠密的矩阵(U,V)直接解决了原始数据A高度稀疏的难题。surprise库也集成了该算法,调用如下:

#Import SVD
from surprise import SVD
#Define the SVD algorithm object
svd = SVD()
#Evaluate the performance in terms of RMSE
evaluate(svd, data, measures=['RMSE'])

 

这篇关于协同滤波模型的推荐算法(ACM暑校-案例学习)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/445133

相关文章

Knife4j+Axios+Redis前后端分离架构下的 API 管理与会话方案(最新推荐)

《Knife4j+Axios+Redis前后端分离架构下的API管理与会话方案(最新推荐)》本文主要介绍了Swagger与Knife4j的配置要点、前后端对接方法以及分布式Session实现原理,... 目录一、Swagger 与 Knife4j 的深度理解及配置要点Knife4j 配置关键要点1.Spri

PostgreSQL的扩展dict_int应用案例解析

《PostgreSQL的扩展dict_int应用案例解析》dict_int扩展为PostgreSQL提供了专业的整数文本处理能力,特别适合需要精确处理数字内容的搜索场景,本文给大家介绍PostgreS... 目录PostgreSQL的扩展dict_int一、扩展概述二、核心功能三、安装与启用四、字典配置方法

Qt QCustomPlot库简介(最新推荐)

《QtQCustomPlot库简介(最新推荐)》QCustomPlot是一款基于Qt的高性能C++绘图库,专为二维数据可视化设计,它具有轻量级、实时处理百万级数据和多图层支持等特点,适用于科学计算、... 目录核心特性概览核心组件解析1.绘图核心 (QCustomPlot类)2.数据容器 (QCPDataC

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

深度解析Java DTO(最新推荐)

《深度解析JavaDTO(最新推荐)》DTO(DataTransferObject)是一种用于在不同层(如Controller层、Service层)之间传输数据的对象设计模式,其核心目的是封装数据,... 目录一、什么是DTO?DTO的核心特点:二、为什么需要DTO?(对比Entity)三、实际应用场景解析

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

Go语言中nil判断的注意事项(最新推荐)

《Go语言中nil判断的注意事项(最新推荐)》本文给大家介绍Go语言中nil判断的注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.接口变量的特殊行为2.nil的合法类型3.nil值的实用行为4.自定义类型与nil5.反射判断nil6.函数返回的

Python get()函数用法案例详解

《Pythonget()函数用法案例详解》在Python中,get()是字典(dict)类型的内置方法,用于安全地获取字典中指定键对应的值,它的核心作用是避免因访问不存在的键而引发KeyError错... 目录简介基本语法一、用法二、案例:安全访问未知键三、案例:配置参数默认值简介python是一种高级编

python 常见数学公式函数使用详解(最新推荐)

《python常见数学公式函数使用详解(最新推荐)》文章介绍了Python的数学计算工具,涵盖内置函数、math/cmath标准库及numpy/scipy/sympy第三方库,支持从基础算术到复杂数... 目录python 数学公式与函数大全1. 基本数学运算1.1 算术运算1.2 分数与小数2. 数学函数