5.4 推荐系统 (Recommendation Systems)


文档摘要

5.4 推荐系统 (Recommendation Systems) 第五章:PyTorch 实战应用领域 - 5.4 推荐系统 (Recommendation Systems) 5.4.1 推荐系统概述 什么是推荐系统? 推荐系统是一种信息过滤系统,旨在预测用户对物品的“偏好”或“兴趣”,并根据这些预测将最相关的物品推荐给用户。这里的“物品”可以是商品、电影、音乐、新闻、文章、社交用户等等,而“偏好”则可以通过用户的显式反馈(如评分、点赞)或隐式行为(如浏览历史、购买记录)来体现。 推荐系统的价值: 提升用户体验: 帮助用户快速发现感兴趣的内容,减少信息过载,提高用户满意度和平台粘性。 增加平台收益: 通过精准推荐,提高商品销量、内容点击率、用户活跃度,直接或间接地增加平台收益。

5.4 推荐系统 (Recommendation Systems)

第五章:PyTorch 实战应用领域 - 5.4 推荐系统 (Recommendation Systems)

5.4.1 推荐系统概述

什么是推荐系统?

推荐系统是一种信息过滤系统,旨在预测用户对物品的“偏好”或“兴趣”,并根据这些预测将最相关的物品推荐给用户。这里的“物品”可以是商品、电影、音乐、新闻、文章、社交用户等等,而“偏好”则可以通过用户的显式反馈(如评分、点赞)或隐式行为(如浏览历史、购买记录)来体现。

推荐系统的价值:

  • 提升用户体验: 帮助用户快速发现感兴趣的内容,减少信息过载,提高用户满意度和平台粘性。

  • 增加平台收益: 通过精准推荐,提高商品销量、内容点击率、用户活跃度,直接或间接地增加平台收益。

  • 个性化服务: 满足不同用户的个性化需求,提供定制化的服务体验,增强用户忠诚度。

推荐系统的分类:

推荐系统可以根据不同的角度进行分类,常见的分类方式包括:

  • 基于内容的推荐 (Content-Based Recommendation): 根据物品的内容特征和用户的历史偏好进行推荐。例如,如果用户过去喜欢科幻电影,那么基于内容的推荐系统会分析科幻电影的特征(如导演、演员、关键词),并推荐具有相似特征的其他电影。

  • 协同过滤推荐 (Collaborative Filtering Recommendation): 基于用户行为数据(如评分、购买记录)进行推荐。它又可以细分为:

    • 基于用户的协同过滤 (User-Based Collaborative Filtering): 找到与目标用户兴趣相似的用户群体,将这些用户喜欢但目标用户未接触过的物品推荐给目标用户。

    • 基于物品的协同过滤 (Item-Based Collaborative Filtering): 分析物品之间的相似性,将与用户过去喜欢的物品相似的物品推荐给用户。

  • 混合推荐 (Hybrid Recommendation): 结合多种推荐方法,利用各自的优点,克服单一方法的局限性,提高推荐效果。例如,可以将内容推荐和协同过滤结合起来,或者采用多种协同过滤算法的集成。

可以用 Mermaid 的 graph TD 图来简单表示推荐系统的分类:

5.4.2 常用推荐算法详解及 PyTorch 代码实践

接下来,我们将详细介绍几种常用的推荐算法,并结合 PyTorch 代码进行实践。为了简化示例,我们将使用一个模拟的小型数据集。

1. 基于内容的推荐 (Content-Based Recommendation)

基于内容的推荐算法的核心思想是:物品的内容特征相似,用户对相似物品的偏好也相似。 算法流程通常包括:

  1. 物品内容特征提取: 对于文本物品(如文章、新闻),可以使用 TF-IDF、Word2Vec 等方法提取关键词向量;对于电影,可以提取导演、演员、类型等特征。

  2. 用户偏好建模: 可以根据用户的历史行为,构建用户的内容偏好向量。例如,计算用户喜欢物品的特征向量的平均值。

  3. 物品相似度计算: 计算物品内容特征向量之间的相似度,例如使用余弦相似度。

  4. 推荐生成: 根据用户的偏好向量和物品的相似度,选择与用户偏好相似度高的物品进行推荐。

PyTorch 代码实践 (简易版):

假设我们有以下电影数据集,包含电影名称和类型:

import torch import torch.nn as nn import torch.optim as optim from sklearn.metrics.pairwise import cosine_similarity # 电影数据集 (电影名, 类型) movies = [ ("Movie A", "Action"), ("Movie B", "Comedy"), ("Movie C", "Action"), ("Movie D", "Drama"), ("Movie E", "Comedy"), ("Movie F", "Action, Sci-Fi"), ("Movie G", "Drama, Romance"), ] # 用户历史观看记录 (用户ID, 电影名) user_history = [ ("User1", "Movie A"), ("User1", "Movie C"), ("User1", "Movie F"), ("User2", "Movie B"), ("User2", "Movie E"), ] # 电影类型到向量的映射 (简化为one-hot encoding) genre_to_index = {"Action": 0, "Comedy": 1, "Drama": 2, "Sci-Fi": 3, "Romance": 4} num_genres = len(genre_to_index) def get_movie_features(movie_genres): features = torch.zeros(num_genres) genres = movie_genres.split(", ") # 处理多类型电影 for genre in genres: if genre in genre_to_index: features[genre_to_index[genre]] = 1 return features # 构建电影特征矩阵 movie_features = {} for movie_name, genres in movies: movie_features[movie_name] = get_movie_features(genres) # 用户偏好建模 (简单平均用户观看过的电影的特征向量) user_profiles = {} for user_id, movie_name in user_history: if user_id not in user_profiles: user_profiles[user_id] = torch.zeros(num_genres) user_profiles[user_id] += movie_features[movie_name] for user_id in user_profiles: watched_count = sum(1 for u, m in user_history if u == user_id) # 统计观看电影数量 user_profiles[user_id] /= watched_count # 平均化 # 物品相似度计算 (使用余弦相似度) def calculate_similarity(movie1_name, movie2_name): feature1 = movie_features[movie1_name].numpy().reshape(1, -1) # 转换为numpy array 并 reshape 成二维 feature2 = movie_features[movie2_name].numpy().reshape(1, -1) return cosine_similarity(feature1, feature2)[0][0] # 推荐生成 (为 User1 推荐电影) user_id_to_recommend = "User1" user_profile = user_profiles[user_id_to_recommend] recommended_movies = [] for movie_name, _ in movies: if movie_name not in [m for u, m in user_history if u == user_id_to_recommend]: # 排除用户已看过的电影 similarity_score = calculate_similarity(list(movie_features.keys())[[list(movie_features.keys()).index(m) for u, m in user_history if u == user_id_to_recommend][0]], movie_name) # 与用户看过的第一部电影计算相似度 (简化) # 更完善的方法应该计算与用户profile的相似度,这里简化处理 similarity_to_profile = cosine_similarity(user_profile.reshape(1,-1).numpy(), movie_features[movie_name].reshape(1,-1).numpy())[0][0] # 计算与用户profile的相似度 recommended_movies.append((movie_name, similarity_to_profile)) recommended_movies.sort(key=lambda x: x[1], reverse=True) # 按相似度排序 print(f"为用户 {user_id_to_recommend} 推荐的电影:") for movie_name, score in recommended_movies: print(f"- {movie_name}: 相似度 {score:.4f}")

代码详解:

  • get_movie_features 函数: 将电影类型转换为 one-hot 向量表示。

  • 构建电影特征矩阵: movie_features 字典存储了每个电影的特征向量。

  • 用户偏好建模: user_profiles 字典存储了每个用户的偏好向量,这里简单地将用户观看过的电影的特征向量平均作为用户偏好。

  • 物品相似度计算: calculate_similarity 函数使用余弦相似度计算电影之间的相似度。

  • 推荐生成: 遍历所有电影,计算与用户偏好向量的相似度,并排序推荐。

需要注意的是,这是一个非常简化的示例,实际应用中:

  • 内容特征提取会更复杂,例如使用 NLP 技术处理文本描述,或使用图像特征提取技术处理图像。

  • 用户偏好建模可以考虑时间因素、用户行为权重等。

  • 相似度计算方法也可能更复杂,例如考虑特征的权重。

2. 协同过滤推荐 (Collaborative Filtering Recommendation)

协同过滤是推荐系统中应用最广泛的技术之一。它基于“物以类聚,人以群分”的思想,分为基于用户的协同过滤和基于物品的协同过滤。

2.1 基于用户的协同过滤 (User-Based Collaborative Filtering)

基于用户的协同过滤的核心思想是:如果用户 A 和用户 B 对某些物品有相似的偏好,那么他们对其他物品的偏好也可能相似。 算法流程通常包括:

  1. 用户相似度计算: 基于用户对物品的评分或行为数据,计算用户之间的相似度。常用的相似度度量方法包括余弦相似度、皮尔逊相关系数等。

  2. 找到相似用户: 对于目标用户,找到与其相似度最高的 K 个用户(称为 K 近邻用户)。

  3. 推荐生成: 将 K 近邻用户喜欢但目标用户未接触过的物品推荐给目标用户。推荐的排序可以根据相似用户的偏好程度进行加权。

PyTorch 代码实践 (简易版):

假设我们有以下用户-电影评分数据:

# 用户-电影评分数据 (用户ID, 电影名, 评分) ratings = [ ("User1", "Movie A", 5), ("User1", "Movie C", 4), ("User1", "Movie F", 5), ("User2", "Movie B", 4), ("User2", "Movie E", 5), ("User3", "Movie A", 3), ("User3", "Movie B", 3), ("User3", "Movie C", 5), ("User3", "Movie D", 2), ("User4", "Movie D", 4), ("User4", "Movie G", 5), ] # 构建用户-物品评分矩阵 user_movie_matrix = {} for user_id, movie_name, rating in ratings: if user_id not in user_movie_matrix: user_movie_matrix[user_id] = {} user_movie_matrix[user_id][movie_name] = rating # 用户相似度计算 (余弦相似度) def calculate_user_similarity(user1_id, user2_id): user1_ratings = user_movie_matrix.get(user1_id, {}) user2_ratings = user_movie_matrix.get(user2_id, {}) # 找到共同评分的电影 common_movies = set(user1_ratings.keys()) & set(user2_ratings.keys()) if not common_movies: return 0.0 # 没有共同评分,相似度为0 user1_vector = torch.tensor([user1_ratings[movie] for movie in common_movies]) user2_vector = torch.tensor([user2_ratings[movie] for movie in common_movies]) return nn.functional.cosine_similarity(user1_vector.float().unsqueeze(0), user2_vector.float().unsqueeze(0)).item() # 注意类型转换和维度 # 找到 K 近邻用户 (这里 K=2) def find_knn_users(target_user_id, K=2): user_similarities = {} for user_id in user_movie_matrix: if user_id != target_user_id: similarity = calculate_user_similarity(target_user_id, user_id) user_similarities[user_id] = similarity knn_users = sorted(user_similarities.items(), key=lambda x: x[1], reverse=True)[:K] # 按相似度排序取前K个 return knn_users # 推荐生成 (为 User4 推荐电影) target_user_id = "User4" knn_users = find_knn_users(target_user_id) recommended_movies = {} for neighbor_user_id, similarity_score in knn_users: neighbor_ratings = user_movie_matrix[neighbor_user_id] for movie_name, rating in neighbor_ratings.items(): if movie_name not in user_movie_matrix.get(target_user_id, {}): # 目标用户未看过的电影 if movie_name not in recommended_movies: recommended_movies[movie_name] = 0 recommended_movies[movie_name] += rating * similarity_score # 加权评分 recommended_movies_sorted = sorted(recommended_movies.items(), key=lambda x: x[1], reverse=True) # 按加权评分排序 print(f"为用户 {target_user_id} 推荐的电影 (基于用户的协同过滤):") for movie_name, weighted_rating in recommended_movies_sorted: print(f"- {movie_name}: 加权评分 {weighted_rating:.4f}")

代码详解:

  • calculate_user_similarity 函数: 计算用户之间的余弦相似度,只考虑共同评分的电影。

  • find_knn_users 函数: 找到目标用户的 K 近邻用户。

  • 推荐生成: 遍历 K 近邻用户的评分,将目标用户未看过的电影加入推荐列表,并根据相似度和邻居用户的评分进行加权。

2.2 基于物品的协同过滤 (Item-Based Collaborative Filtering)

基于物品的协同过滤的核心思想是:如果物品 A 和物品 B 经常被用户同时喜欢,那么它们可能具有相似的属性。 算法流程通常包括:

  1. 物品相似度计算: 基于用户对物品的评分或行为数据,计算物品之间的相似度。常用的相似度度量方法同样包括余弦相似度、调整的余弦相似度等。

  2. 用户历史偏好分析: 分析目标用户过去喜欢的物品。

  3. 推荐生成: 将与用户过去喜欢的物品相似的物品推荐给目标用户。推荐的排序可以根据物品的相似度和用户对历史物品的偏好程度进行加权。

PyTorch 代码实践 (简易版):

# (沿用之前的 ratings 数据) # 构建物品-用户倒排表 (电影 -> 用户列表) movie_user_matrix = {} for user_id, movie_name, rating in ratings: if movie_name not in movie_user_matrix: movie_user_matrix[movie_name] = {} movie_user_matrix[movie_name][user_id] = rating # 物品相似度计算 (余弦相似度) def calculate_item_similarity(movie1_name, movie2_name): movie1_users = movie_user_matrix.get(movie1_name, {}) movie2_users = movie_user_matrix.get(movie2_name, {}) # 找到共同评分的用户 common_users = set(movie1_users.keys()) & set(movie2_users.keys()) if not common_users: return 0.0 # 没有共同用户,相似度为0 movie1_vector = torch.tensor([movie1_users[user] for user in common_users]) movie2_vector = torch.tensor([movie2_users[user] for user in common_users]) return nn.functional.cosine_similarity(movie1_vector.float().unsqueeze(0), movie2_vector.float().unsqueeze(0)).item() # 注意类型转换和维度 # 推荐生成 (为 User4 推荐电影) target_user_id = "User4" user_rated_movies = user_movie_matrix.get(target_user_id, {}).keys() # 用户已评分的电影 recommended_movies = {} for rated_movie in user_rated_movies: for movie_name in movie_user_matrix: # 遍历所有电影 if movie_name != rated_movie and movie_name not in user_rated_movies: # 不是已评分的电影 similarity_score = calculate_item_similarity(rated_movie, movie_name) if movie_name not in recommended_movies: recommended_movies[movie_name] = 0 recommended_movies[movie_name] += similarity_score * user_movie_matrix[target_user_id][rated_movie] # 加权评分 recommended_movies_sorted = sorted(recommended_movies.items(), key=lambda x: x[1], reverse=True) # 按加权评分排序 print(f"为用户 {target_user_id} 推荐的电影 (基于物品的协同过滤):") for movie_name, weighted_rating in recommended_movies_sorted: print(f"- {movie_name}: 加权评分 {weighted_rating:.4f}")

代码详解:

  • calculate_item_similarity 函数: 计算物品之间的余弦相似度,只考虑共同评分的用户。

  • 推荐生成: 遍历用户已评分的电影,找到与其相似的电影,并根据相似度和用户对历史物品的评分进行加权。

3. 矩阵分解 (Matrix Factorization)

矩阵分解是一种常用的协同过滤算法,它将用户-物品评分矩阵分解为两个低维矩阵:用户隐因子矩阵和物品隐因子矩阵。通过学习用户和物品的隐因子向量,可以预测用户对未评分物品的评分。

模型结构:

假设用户数量为 U,物品数量为 I,评分矩阵为 R (U x I)。矩阵分解的目标是找到两个低维矩阵 P (U x K) 和 Q (I x K),其中 K 是隐因子的维度,使得 P * Q^T 近似于 R。

  • P (用户隐因子矩阵): 每一行代表一个用户,每一列代表一个隐因子。P[u, k] 表示用户 u 在第 k 个隐因子上的强度。

  • Q (物品隐因子矩阵): 每一行代表一个物品,每一列代表一个隐因子。Q[i, k] 表示物品 i 在第 k 个隐因子上的强度。

预测用户 u 对物品 i 的评分可以通过计算用户隐因子向量 p_u 和物品隐因子向量 q_i 的点积得到:

r_hat_ui = p_u * q_i^T = sum(P[u, k] * Q[i, k] for k in range(K))

PyTorch 代码实践 (矩阵分解模型):

class MatrixFactorization(nn.Module): def __init__(self, num_users, num_items, embedding_dim=64): super(MatrixFactorization, self).__init__() self.user_embedding = nn.Embedding(num_users, embedding_dim) # 用户embedding层 self.item_embedding = nn.Embedding(num_items, embedding_dim) # 物品embedding层 self.user_bias = nn.Embedding(num_users, 1) # 用户bias self.item_bias = nn.Embedding(num_items, 1) # 物品bias # 初始化 embedding nn.init.normal_(self.user_embedding.weight, std=0.01) nn.init.normal_(self.item_embedding.weight, std=0.01) nn.init.zeros_(self.user_bias.weight) nn.init.zeros_(self.item_bias.weight) def forward(self, user_indices, item_indices): user_embeds = self.user_embedding(user_indices) item_embeds = self.item_embedding(item_indices) user_biases = self.user_bias(user_indices).squeeze(1) # 移除维度为1的维度 item_biases = self.item_bias(item_indices).squeeze(1) # 预测评分 = 用户embedding点积 + 用户bias + 物品bias predictions = (user_embeds * item_embeds).sum(dim=1) + user_biases + item_biases return predictions # 数据准备 (将之前的 ratings 数据转换为模型输入格式) user_ids = sorted(list(set([r[0] for r in ratings]))) movie_names = sorted(list(set([r[1] for r in ratings]))) user_to_index = {user_id: index for index, user_id in enumerate(user_ids)} movie_to_index = {movie_name: index for index, movie_name in enumerate(movie_names)} train_data = [] for user_id, movie_name, rating in ratings: train_data.append((user_to_index[user_id], movie_to_index[movie_name], rating)) user_indices = torch.tensor([data[0] for data in train_data]) item_indices = torch.tensor([data[1] for data in train_data]) rating_targets = torch.tensor([data[2] for data in train_data]).float() # 目标评分 # 模型训练 num_users = len(user_ids) num_items = len(movie_names) embedding_dim = 32 # 隐因子维度 model = MatrixFactorization(num_users, num_items, embedding_dim) loss_func = nn.MSELoss() # 均方误差损失函数 optimizer = optim.Adam(model.parameters(), lr=0.01) # Adam优化器 epochs = 100 for epoch in range(epochs): optimizer.zero_grad() # 梯度清零 predictions = model(user_indices, item_indices) # 前向传播 loss = loss_func(predictions, rating_targets) # 计算loss loss.backward() # 反向传播 optimizer.step() # 更新参数 if (epoch+1) % 10 == 0: print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}") # 预测评分 (预测 User4 对 Movie B 的评分) user_index_predict = user_to_index["User4"] movie_index_predict = movie_to_index["Movie B"] predicted_rating = model(torch.tensor([user_index_predict]), torch.tensor([movie_index_predict])).item() print(f"预测 User4 对 Movie B 的评分: {predicted_rating:.2f}") # 推荐生成 (为 User4 推荐电影) target_user_index = user_to_index["User4"] user_index_tensor = torch.tensor([target_user_index] * num_items) # 重复用户index,用于预测所有物品 item_index_tensor = torch.arange(num_items) # 所有物品的index with torch.no_grad(): # 预测阶段不需要梯度 predictions_all_items = model(user_index_tensor, item_index_tensor) movie_index_to_name = {index: name for name, index in movie_to_index.items()} recommended_movies = [] for item_index in range(num_items): movie_name = movie_index_to_name[item_index] if movie_name not in user_movie_matrix.get("User4", {}): # 排除用户已评分的电影 recommended_movies.append((movie_name, predictions_all_items[item_index].item())) recommended_movies.sort(key=lambda x: x[1], reverse=True) # 按预测评分排序 print(f"为用户 User4 推荐的电影 (矩阵分解):") for movie_name, predicted_rating in recommended_movies: print(f"- {movie_name}: 预测评分 {predicted_rating:.2f}")

代码详解:

  • MatrixFactorization 类: 定义了矩阵分解模型,包含用户和物品的 embedding 层以及 bias 项。

  • 数据准备: 将用户ID和电影名转换为索引,构建训练数据。

  • 模型训练: 使用 MSELoss 和 Adam 优化器训练模型。

  • 预测评分: 使用训练好的模型预测用户对特定物品的评分。

  • 推荐生成: 预测用户对所有物品的评分,并排序推荐用户未评分的物品。

模型结构 Mermaid 图:

5.4.3 混合推荐系统

在实际应用中,单一的推荐算法往往难以达到最佳效果。混合推荐系统通过结合多种推荐算法的优点,可以提高推荐的准确性和多样性。常见的混合策略包括:

  • 加权混合 (Weighted Hybridization): 对不同推荐算法的结果进行加权求和,得到最终的推荐列表。

  • 切换混合 (Switching Hybridization): 根据不同的场景或用户特征,选择不同的推荐算法。

  • 组合混合 (Mixed Hybridization): 将不同推荐算法的结果组合在一起,例如,先使用协同过滤生成一部分推荐,再使用内容推荐补充另一部分。

  • 级联混合 (Cascade Hybridization): 将一个推荐算法的结果作为另一个推荐算法的输入,例如,先使用内容推荐过滤掉不相关的物品,再使用协同过滤对剩余物品进行排序。

混合推荐系统的选择需要根据具体的应用场景和数据特点进行权衡。

5.4.4 推荐系统评估指标

评估推荐系统的效果至关重要。常用的评估指标包括:

  • 准确率 (Precision) 和召回率 (Recall): 衡量推荐列表中有多少物品是用户真正感兴趣的,以及用户感兴趣的物品有多少被推荐出来了。

  • F1 值 (F1-score): 准确率和召回率的调和平均值,综合衡量推荐效果。

  • 平均精度均值 (Mean Average Precision, MAP): 衡量多个用户在多个推荐列表上的平均精度。

  • 归一化折损累计增益 (Normalized Discounted Cumulative Gain, NDCG): 考虑推荐列表中物品的排序位置,位置越靠前的相关物品权重越高。

  • 点击率 (Click-Through Rate, CTR): 用户点击推荐物品的比例。

  • 转化率 (Conversion Rate, CVR): 用户在点击推荐物品后完成特定行为(如购买、注册)的比例。

选择合适的评估指标需要根据具体的业务目标和推荐场景。

5.4.5 总结与展望

本节深入探讨了推荐系统的概念、类型、常用算法,并结合 PyTorch 进行了代码实践,包括基于内容的推荐、协同过滤推荐(基于用户和基于物品)以及矩阵分解。这些算法是构建现代推荐系统的基础。

随着深度学习技术的发展,基于神经网络的推荐模型,如神经协同过滤 (Neural Collaborative Filtering, NCF)、深度因子分解机 (DeepFM) 等,在推荐领域取得了显著的成果。PyTorch 框架凭借其灵活性和强大的计算能力,成为研究和开发深度学习推荐模型的首选工具。

未来推荐系统的发展趋势包括:

  • 更加个性化和精细化的推荐: 利用用户更丰富的行为数据和上下文信息,提供更加个性化的推荐。

  • 更加智能和可解释的推荐: 提高推荐算法的可解释性,让用户理解推荐的原因,增强用户信任感。

  • 多目标优化推荐: 同时考虑用户满意度、平台收益、社会公平性等多个目标,实现更全面的推荐效果。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U