推荐系统入门:从“找相似”到协同过滤与矩阵分解

推荐系统入门:从“找相似”到协同过滤与矩阵分解 推荐系统是现代互联网产品中不可或缺的一部分。无论是短视频平台、电商平台还是新闻聚合应用背后都依赖推荐系统来提升用户体验和平台效率。很多初学者会直观地认为“推荐系统不就是找相似的东西吗”——这个理解其实非常接近本质。本文将从这一朴素直觉出发逐步介绍推荐系统的基本原理并通过 Python 代码演示三种典型方法基于内容的推荐、基于用户的协同过滤以及矩阵分解。一、推荐系统的直觉找相似假设你第一次打开一个视频平台系统并不了解你的兴趣。它可能会随机推送一些视频或者展示热门内容。当你点击观看某些视频后系统开始记录你的行为。如果这些视频都带有“人工智能”“编程”等标签系统就会推测你对技术类内容感兴趣并尝试推荐具有相似标签的新视频。这种思路属于基于内容的推荐Content-Based Recommendation。其核心逻辑是每个物品如视频由一组特征表示例如标签、关键词、Embedding 向量用户的兴趣通过其历史交互物品的特征平均或加权得到形成“用户画像”推荐时计算未交互物品与用户画像的相似度选择最相似的若干项。下面是一个简化实现importnumpyasnpfromsklearn.metrics.pairwiseimportcosine_similarity# 1. 定义视频库每个视频用标签向量表示videos{v1:{title:AI入门,features:np.array([1,0,0,1])},# [科技, 娱乐, 体育, 教育]v2:{title:NBA集锦,features:np.array([0,0,1,0])},v3:{title:Python教程,features:np.array([1,0,0,1])},v4:{title:明星八卦,features:np.array([0,1,0,0])},v5:{title:机器学习实战,features:np.array([1,0,0,1])},v6:{title:足球世界杯,features:np.array([0,0,1,0])},}# 2. 用户观看历史假设用户看了 v1 和 v3user_watched[v1,v3]# 3. 构建用户画像平均已看视频的特征向量user_profilenp.mean([videos[vid][features]forvidinuser_watched],axis0)print(用户画像向量:,user_profile)# 输出: [1. 0. 0. 1.]# 4. 计算所有未看视频与用户画像的相似度scores{}forvid,infoinvideos.items():ifvidnotinuser_watched:simcosine_similarity([user_profile],[info[features]])[0][0]scores[vid]sim# 5. 按相似度排序推荐 Top-2recommendedsorted(scores.items(),keylambdax:x[1],reverseTrue)[:2]print(\n推荐结果:)forvid,scoreinrecommended:print(f{videos[vid][title]}(相似度:{score:.2f}))用户画像向量: [1. 0. 0. 1.] 推荐结果: 机器学习实战 (相似度: 1.00) NBA集锦 (相似度: 0.00)该方法简单直观但依赖高质量的物品特征且难以发现用户潜在的新兴趣比如从编程转向数据可视化。二、协同过滤利用群体智慧为克服上述局限推荐系统引入了协同过滤Collaborative Filtering。其基本假设是行为相似的用户兴趣也相似。以用户 A 为例如果他和用户 B 都喜欢视频 v1 和 v2而用户 B 还喜欢 v3那么系统可以推测 A 也可能喜欢 v3。这就是基于用户的协同过滤。实现步骤包括构建用户-物品评分矩阵计算用户之间的相似度如余弦相似度利用相似用户的评分加权预测目标用户对未交互物品的偏好。以下是基于显式评分的协同过滤示例importpandasaspdfromsklearn.metrics.pairwiseimportcosine_similarity# 1. 用户-物品评分矩阵NaN 表示未评分ratingspd.DataFrame({User:[A,A,B,B,C,C,D],Item:[v1,v2,v1,v3,v2,v3,v1],Rating:[5,3,4,5,2,4,5]})# 转为用户-物品矩阵rating_matrixratings.pivot(indexUser,columnsItem,valuesRating)print(原始评分矩阵:)print(rating_matrix)# 2. 填充 NaN 为 0简化处理实际中可中心化或跳过rating_matrix_filledrating_matrix.fillna(0)# 3. 计算用户相似度余弦相似度user_simcosine_similarity(rating_matrix_filled)user_sim_dfpd.DataFrame(user_sim,indexrating_matrix.index,columnsrating_matrix.index)print(\n用户相似度矩阵:)print(user_sim_df)# 4. 为目标用户 A 推荐target_userAtarget_ratingsrating_matrix.loc[target_user]# 找出 A 没评过分的物品items_not_ratedtarget_ratings[target_ratings.isna()].index# 预测评分pred_scores{}foriteminitems_not_rated:# 所有评过分的用户users_who_ratedrating_matrix[item].dropna().indexiflen(users_who_rated)0:continuesim_scores[]weighted_ratings[]foruserinusers_who_rated:ifusertarget_user:continuesimuser_sim_df.loc[target_user,user]ratingrating_matrix.loc[user,item]sim_scores.append(sim)weighted_ratings.append(sim*rating)ifsum(sim_scores)0:predrating_matrix[item].mean()# 回退到平均分else:predsum(weighted_ratings)/sum(sim_scores)pred_scores[item]pred# 排序推荐recommendedsorted(pred_scores.items(),keylambdax:x[1],reverseTrue)print(f\n为用户{target_user}推荐:)foritem,scoreinrecommended:print(f{item}: 预测评分 {score:.2f})原始评分矩阵: Item v1 v2 v3 User A 5.0 3.0 NaN B 4.0 NaN 5.0 C NaN 2.0 4.0 D 5.0 NaN NaN 用户相似度矩阵: User A B C D User A 1.000000 0.535672 0.230089 0.857493 B 0.535672 1.000000 0.698430 0.624695 C 0.230089 0.698430 1.000000 0.000000 D 0.857493 0.624695 0.000000 1.000000 为用户 A 推荐: v3: 预测评分 4.70协同过滤无需物品特征能发现跨类别的关联例如“看《线性代数》的人也喜欢《机器学习导论》”但面临冷启动新用户无行为和数据稀疏问题。三、矩阵分解从稀疏数据中挖掘潜在因子为更高效地处理稀疏评分矩阵矩阵分解Matrix Factorization被广泛采用。其思想是将原始的用户-物品评分矩阵RRR分解为两个低维隐向量矩阵UUU用户因子和VVV物品因子使得R≈UVTR \approx UV^TR≈UVT。每个用户和物品都被映射到一个共享的“潜在语义空间”中。例如一个维度可能代表“技术深度”另一个代表“娱乐性”。模型通过优化过程自动学习这些抽象特征。使用surprise库可快速实现 SVD奇异值分解风格的矩阵分解fromsurpriseimportDataset,Reader,SVDfromsurprise.model_selectionimporttrain_test_splitimportpandasaspd# 1. 准备数据data_dfpd.DataFrame({user:[A,A,B,B,C,C,D],item:[v1,v2,v1,v3,v2,v3,v1],rating:[5,3,4,5,2,4,5]})readerReader(rating_scale(1,5))dataDataset.load_from_df(data_df[[user,item,rating]],reader)# 2. 划分训练/测试集trainset,testsettrain_test_split(data,test_size0.2,random_state42)# 3. 训练 SVD 模型矩阵分解modelSVD(n_factors10,n_epochs20,lr_all0.005,reg_all0.02)model.fit(trainset)# 4. 为用户 A 预测未交互的物品all_itemsdata_df[item].unique()user_A_itemsset(data_df[data_df[user]A][item])items_to_predict[itemforiteminall_itemsifitemnotinuser_A_items]preds[]foriteminitems_to_predict:predmodel.predict(A,item)preds.append((item,pred.est))# 排序preds.sort(keylambdax:x[1],reverseTrue)print(SVD 矩阵分解推荐结果用户 A:)foritem,scoreinpreds:print(f{item}: 预测评分 {score:.2f})SVD 矩阵分解推荐结果用户 A: v3: 预测评分 3.71矩阵分解在 Netflix Prize 等竞赛中大放异彩成为工业界经典方法。它能有效缓解数据稀疏性但仍是黑盒模型且对新用户/新物品仍存在冷启动挑战。四、总结与展望从“找相似”出发我们逐步深入到协同过滤和矩阵分解可以看到推荐系统的发展脉络基于内容依赖特征可解释性强协同过滤利用群体行为发现隐性关联矩阵分解通过低维嵌入建模复杂偏好。实际系统往往是多种方法的融合并结合深度学习、上下文信息、实时反馈等机制。对于初学者而言理解这三种基础方法是迈向更复杂推荐架构的重要一步。后续可探索的方向包括隐式反馈建模如 ALS 算法、序列推荐如 GRU4Rec、多任务学习、以及基于图神经网络的推荐系统。无论技术如何演进“理解用户、连接内容”的核心目标始终不变。