/* 基于物品的协同过滤算法 */
// 假设有一个User类,包含id和name属性
// 假设有一个Food类,包含id和name属性
// 假设有一个Rating类,包含userId, foodId和score属性,表示用户对美食的评分
// 假设有一个RatingRepository接口,用于从数据库中查询评分数据
// 假设有一个FoodRepository接口,用于从数据库中查询美食数据
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class FoodRecommendationService {
@Autowired
private RatingRepository ratingRepository;
@Autowired
private FoodRepository foodRepository;
// 计算两个用户之间的相似度,使用皮尔逊相关系数
private double similarity(User u1, User u2) {
// 获取两个用户共同评分过的美食列表
List<Food> commonFoods = ratingRepository.findCommonFoodsByUsers(u1.getId(), u2.getId());
// 如果没有共同评分过的美食,返回0
if (commonFoods.isEmpty()) {
return 0;
}
// 计算两个用户的评分平均值
double u1Mean = ratingRepository.findAverageScoreByUser(u1.getId());
double u2Mean = ratingRepository.findAverageScoreByUser(u2.getId());
// 计算两个用户的评分标准差
double u1Std = ratingRepository.findStandardDeviationByUser(u1.getId());
double u2Std = ratingRepository.findStandardDeviationByUser(u2.getId());
// 如果有一个用户的标准差为0,返回0
if (u1Std == 0 || u2Std == 0) {
return 0;
}
// 计算两个用户的评分协方差
double cov = 0;
for (Food food : commonFoods) {
double u1Score = ratingRepository.findScoreByUserAndFood(u1.getId(), food.getId());
double u2Score = ratingRepository.findScoreByUserAndFood(u2.getId(), food.getId());
cov += (u1Score - u1Mean) * (u2Score - u2Mean);
}
cov /= commonFoods.size();
// 计算两个用户的皮尔逊相关系数
double pearson = cov / (u1Std * u2Std);
return pearson;
}
// 根据用户评分美食来进行个性化推荐,使用基于用户的协同过滤算法
public List<Food> recommend(User user) {
// 获取所有的用户列表
List<User> users = ratingRepository.findAllUsers();
// 获取目标用户已经评分过的美食列表
List<Food> ratedFoods = ratingRepository.findFoodsByUser(user.getId());
// 获取所有的美食列表
List<Food> foods = foodRepository.findAllFoods();
// 创建一个存储每个美食的预测评分的映射表
Map<Food, Double> predictions = new HashMap<>();
// 遍历每个未评分过的美食
for (Food food : foods) {
if (!ratedFoods.contains(food)) {
// 初始化预测评分为0
predictions.put(food, 0.0);
// 计算目标用户的评分平均值
double userMean = ratingRepository.findAverageScoreByUser(user.getId());
// 初始化分子和分母为0
double numerator = 0;
double denominator = 0;
// 遍历每个其他用户
for (User other : users) {
if (!other.equals(user)) {
// 获取其他用户对该美食的评分,如果没有评分则跳过
Double otherScore = ratingRepository.findScoreByUserAndFood(other.getId(), food.getId());
if (otherScore != null) {
// 计算其他用户的评分平均值
double otherMean = ratingRepository.findAverageScoreByUser(other.getId());
// 计算目标用户和其他用户之间的相似度
double sim = similarity(user, other);
// 累加分子和分母
numerator += sim * (otherScore - otherMean);
denominator += Math.abs(sim);
}
}
}
// 如果分母不为0,计算预测评分并更新映射表
if (denominator != 0) {
double prediction = userMean + numerator / denominator;
predictions.put(food, prediction);
}
}
}
// 创建一个存储推荐美食的列表
List<Food> recommendations = new ArrayList<>();
// 根据预测评分从高到低排序美食
predictions.entrySet().stream()
.sorted(Map.Entry.<Food, Double>comparingByValue().reversed())
.forEach(entry -> {
// 将前10个美食加入推荐列表
if (recommendations.size() < 10) {
recommendations.add(entry.getKey());
}
});
// 返回推荐列表
return recommendations;
}
}
推荐算法G-2
最新推荐文章于 2024-10-08 15:07:49 发布