使用R实现User based CF训练测试拆分及评分预测方法咨询
1 训练集与测试集拆分实现
因为你的数据集是行对应用户、列对应电影的评分矩阵,拆分时需要避免数据泄露,采用按用户分层掩蔽的方案:
- 对每个用户,随机选取20%~30%的已评分条目设为掩蔽状态,这部分的真实评分作为测试集的标注
- 剩余已评分条目保留,作为训练集用来计算用户相似度
拆分代码示例:
# 设置随机种子保证可复现 set.seed(123) train_data <- final_data test_mask <- matrix(FALSE, nrow = nrow(final_data), ncol = ncol(final_data)) test_rate <- 0.2 # 测试集占已评分数据的20% for (u in 1:nrow(final_data)) { # 找到当前用户所有已评分的列索引 rated_cols <- which(!is.na(final_data[u, ])) # 随机选test_rate比例的列作为测试集 test_cols <- sample(rated_cols, size = ceiling(length(rated_cols)*test_rate)) test_mask[u, test_cols] <- TRUE # 训练集掩蔽测试集的评分 train_data[u, test_cols] <- NA }
运行后train_data是训练用评分矩阵,test_mask标记了测试集位置,注意相似度计算要基于train_data而非全量数据,避免数据泄露。
2 用户相似度矩阵计算优化
你现有代码用嵌套循环计算10000*10000的相似度矩阵效率极低,推荐改用向量化实现,速度提升至少10倍:
# 替换你现有嵌套循环的实现 # 先对每行做标准化,处理缺失值 train_norm <- train_data train_norm[is.na(train_norm)] <- 0 # 计算每行的L2范数 row_norms <- sqrt(rowSums(train_norm^2)) # 余弦相似度 = 矩阵叉乘 / 范数外积 user_similarities <- tcrossprod(train_norm) / outer(row_norms, row_norms) diag(user_similarities) <- 0 # 自身相似度设为0 user_similarities[is.na(user_similarities)] <- 0 rownames(user_similarities) <- rownames(train_data) colnames(user_similarities) <- rownames(train_data) user_similarities <- round(user_similarities, 3)
3 评分预测实现步骤与代码
3.1 预测核心步骤
- 对每个目标用户u,筛选出Top K个相似度最高的邻居(K通常取20~100,可调整优化),仅保留相似度为正的邻居避免负权重干扰
- 对用户u未评分的每部电影i,提取所有给i评过分的邻居用户
- 对邻居的评分做加权平均,权重为对应邻居和u的相似度,得到u对i的预测评分:
预测评分公式:( pred(u,i) = \frac{\sum_{v \in N(u,i)} sim(u,v) * r(v,i)}{\sum_{v \in N(u,i)} |sim(u,v)|} )
其中N(u,i)是给i评过分的u的邻居集合,r(v,i)是用户v对i的真实评分
3.2 预测代码实现
# 可调参数:邻居数量K K <- 50 # 初始化预测矩阵,和原矩阵维度一致 pred_matrix <- matrix(NA, nrow = nrow(train_data), ncol = ncol(train_data)) rownames(pred_matrix) <- rownames(train_data) colnames(pred_matrix) <- colnames(train_data) for (u in 1:nrow(train_data)) { # 取当前用户的Top K正相似度邻居 sim_vec <- user_similarities[u, ] top_neighbors <- order(sim_vec, decreasing = TRUE)[1:K] top_neighbors <- top_neighbors[sim_vec[top_neighbors] > 0] # 过滤负相似度 top_sim <- sim_vec[top_neighbors] # 计算当前用户所有未评分电影的预测分 unrated_cols <- which(is.na(train_data[u, ])) for (i in unrated_cols) { # 提取邻居中对i有评分的用户 neighbor_rated <- which(!is.na(train_data[top_neighbors, i])) if (length(neighbor_rated) == 0) { # 没有邻居评分时,用当前用户的平均评分填充 pred_matrix[u, i] <- mean(train_data[u, ], na.rm = TRUE) next } # 加权计算预测分 sum_sim_rating <- sum(top_sim[neighbor_rated] * train_data[top_neighbors[neighbor_rated], i]) sum_sim <- sum(abs(top_sim[neighbor_rated])) pred_matrix[u, i] <- sum_sim_rating / sum_sim } } # 输出结果四舍五入到1位小数和示例输出匹配 pred_matrix <- round(pred_matrix, 1)
运行完成后pred_matrix就是你需要的预测结果矩阵,你可以通过pred_matrix[test_mask]提取测试集的预测值,和final_data[test_mask]的真实值计算RMSE等评估指标。
内容的提问来源于stack exchange,提问作者Anilaaryan
相关产品推荐
相关产品推荐

