基于物品的协同过滤推荐算法实现(Java电商平台)

下面我将为你实现一个基于物品的协同过滤推荐算法,适用于Java电商平台。这个实现包括核心算法、相似度计算和推荐生成。

1. 数据模型 

 首先定义我们需要的数据模型:

public class Item {
    private String itemId;    // 商品ID
    private String name;      // 商品名称
    // 其他商品属性...
    
    // 构造方法、getter和setter
}

public class User {
    private String userId;    // 用户ID
    private String username; // 用户名
    // 其他用户属性...
    
    // 构造方法、getter和setter
}

public class UserBehavior {
    private String userId;    // 用户ID
    private String itemId;    // 商品ID
    private double preference; // 偏好分数(如评分、购买次数等)
    private long timestamp;   // 行为时间戳
    
    // 构造方法、getter和setter
}

 2. 相似度计算

基于物品的协同过滤核心是计算物品之间的相似度: 

public class ItemSimilarity {
    
    /**
     * 计算物品之间的余弦相似度
     * @param itemPrefMap 物品-用户偏好矩阵: Map<itemId, Map<userId, preference>>
     * @return 物品相似度矩阵: Map<itemId, Map<itemId, similarity>>
     */
    public Map<String, Map<String, Double>> calculateCosineSimilarity(
            Map<String, Map<String, Double>> itemPrefMap) {
        
        Map<String, Map<String, Double>> similarityMatrix = new HashMap<>();
        
        // 获取所有物品列表
        List<String> itemIds = new ArrayList<>(itemPrefMap.keySet());
        
        // 计算每对物品之间的相似度
        for (int i = 0; i < itemIds.size(); i++) {
            String itemId1 = itemIds.get(i);
            Map<String, Double> userPrefs1 = itemPrefMap.get(itemId1);
            
            // 初始化相似度矩阵
            similarityMatrix.put(itemId1, new HashMap<>());
            
            for (int j = i; j < itemIds.size(); j++) {
                String itemId2 = itemIds.get(j);
                
                if (itemId1.equals(itemId2)) {
                    // 相同物品相似度为1
                    similarityMatrix.get(itemId1).put(itemId2, 1.0);
                    continue;
                }
                
                Map<String, Double> userPrefs2 = itemPrefMap.get(itemId2);
                
                // 计算两个物品的共同用户
                Set<String> commonUsers = new HashSet<>(userPrefs1.keySet());
                commonUsers.retainAll(userPrefs2.keySet());
                
                if (commonUsers.isEmpty()) {
                    // 没有共同用户,相似度为0
                    similarityMatrix.get(itemId1).put(itemId2, 0.0);
                    similarityMatrix.get(itemId2).put(itemId1, 0.0);
                    continue;
                }
                
                // 计算余弦相似度的分子和分母
                double dotProduct = 0.0;
                double norm1 = 0.0;
                double norm2 = 0.0;
                
                for (String userId : commonUsers) {
                    double pref1 = userPrefs1.get(userId);
                    double pref2 = userPrefs2.get(userId);
                    
                    dotProduct += pref1 * pref2;
                    norm1 += Math.pow(pref1, 2);
                    norm2 += Math.pow(pref2, 2);
                }
                
                // 计算余弦相似度
                double similarity = dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
                
                // 对称矩阵,所以两个方向都存储
                similarityMatrix.get(itemId1).put(itemId2, similarity);
                
                // 确保对称矩阵的另一半也被填充
                if (!similarityMatrix.containsKey(itemId2)) {
                    similarityMatrix.put(itemId2, new HashMap<>());
                }
                similarityMatrix.get(itemId2).put(itemId1, similarity);
            }
        }
        
        return similarityMatrix;
    }
    
    /**
     * 计算物品之间的改进余弦相似度(考虑用户平均评分)
     */
    public Map<String, Map<String, Double>> calculateAdjustedCosineSimilarity(
            Map<String, Map<String, Double>> itemPrefMap,
            Map<String, Double> userAvgPrefMap) {
        
        // 实现类似上面,但在计算时减去用户平均评分
        // ...
        
        return similarityMatrix;
    }
}

 3. 推荐引擎

基于物品相似度生成推荐: 

public class ItemBasedRecommender {
    private Map<String, Map<String, Double>> itemSimilarityMatrix;
    private Map<String, Map<String, Double>> userItemPrefMap; // 用户-物品偏好矩阵
    
    public ItemBasedRecommender(Map<String, Map<String, Double>> itemSimilarityMatrix,
                               Map<String, Map<String, Double>> userItemPrefMap) {
        this.itemSimilarityMatrix = itemSimilarityMatrix;
        this.userItemPrefMap = userItemPrefMap;
    }
    
    /**
     * 为用户推荐物品
     * @param userId 用户ID
     * @param topN 推荐数量
     * @return 推荐物品ID列表,按推荐分数降序排列
     */
    public List<String> recommendItems(String userId, int topN) {
        // 获取用户历史行为物品
        Map<String, Double> userHistory = userItemPrefMap.getOrDefault(userId, new HashMap<>());
        
        // 存储物品的推荐分数
        Map<String, Double> recommendationScores = new HashMap<>();
        
        // 遍历用户历史行为物品
        for (Map.Entry<String, Double> entry : userHistory.entrySet()) {
            String historyItemId = entry.getKey();
            double historyPref = entry.getValue();
            
            // 获取与历史物品相似的物品
            Map<String, Double> similarItems = itemSimilarityMatrix.getOrDefault(historyItemId, new HashMap<>());
            
            // 计算推荐分数
            for (Map.Entry<String, Double> simEntry : similarItems.entrySet()) {
                String candidateItemId = simEntry.getKey();
                double similarity = simEntry.getValue();
                
                // 排除用户已经有过行为的物品
                if (!userHistory.containsKey(candidateItemId)) {
                    double score = recommendationScores.getOrDefault(candidateItemId, 0.0);
                    score += similarity * historyPref;
                    recommendationScores.put(candidateItemId, score);
                }
            }
        }
        
        // 按推荐分数排序并返回topN
        return recommendationScores.entrySet().stream()
                .sorted(Map.Entry.<String, Double>comparingByValue().reversed())
                .limit(topN)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }
}

 4. 数据预处理

 在实际应用中,我们需要将原始用户行为数据转换为算法需要的格式:

public class DataPreprocessor {
    
    /**
     * 将用户行为列表转换为物品-用户偏好矩阵
     */
    public Map<String, Map<String, Double>> convertToItemUserMatrix(List<UserBehavior> behaviors) {
        Map<String, Map<String, Double>> itemUserMatrix = new HashMap<>();
        
        for (UserBehavior behavior : behaviors) {
            String itemId = behavior.getItemId();
            String userId = behavior.getUserId();
            double preference = behavior.getPreference();
            
            itemUserMatrix.putIfAbsent(itemId, new HashMap<>());
            itemUserMatrix.get(itemId).put(userId, preference);
        }
        
        return itemUserMatrix;
    }
    
    /**
     * 将用户行为列表转换为用户-物品偏好矩阵
     */
    public Map<String, Map<String, Double>> convertToUserItemMatrix(List<UserBehavior> behaviors) {
        Map<String, Map<String, Double>> userItemMatrix = new HashMap<>();
        
        for (UserBehavior behavior : behaviors) {
            String userId = behavior.getUserId();
            String itemId = behavior.getItemId();
            double preference = behavior.getPreference();
            
            userItemMatrix.putIfAbsent(userId, new HashMap<>());
            userItemMatrix.get(userId).put(itemId, preference);
        }
        
        return userItemMatrix;
    }
    
    /**
     * 计算每个用户的平均评分
     */
    public Map<String, Double> calculateUserAveragePreference(List<UserBehavior> behaviors) {
        Map<String, Double> sumMap = new HashMap<>();
        Map<String, Integer> countMap = new HashMap<>();
        
        for (UserBehavior behavior : behaviors) {
            String userId = behavior.getUserId();
            double preference = behavior.getPreference();
            
            sumMap.put(userId, sumMap.getOrDefault(userId, 0.0) + preference);
            countMap.put(userId, countMap.getOrDefault(userId, 0) + 1);
        }
        
        Map<String, Double> avgMap = new HashMap<>();
        for (String userId : sumMap.keySet()) {
            avgMap.put(userId, sumMap.get(userId) / countMap.get(userId));
        }
        
        return avgMap;
    }
}

 5. 完整使用示例

public class RecommendationDemo {
    public static void main(String[] args) {
        // 1. 模拟数据
        List<UserBehavior> behaviors = new ArrayList<>();
        behaviors.add(new UserBehavior("u1", "i1", 5.0, System.currentTimeMillis()));
        behaviors.add(new UserBehavior("u1", "i2", 3.0, System.currentTimeMillis()));
        behaviors.add(new UserBehavior("u1", "i3", 4.0, System.currentTimeMillis()));
        behaviors.add(new UserBehavior("u2", "i1", 4.0, System.currentTimeMillis()));
        behaviors.add(new UserBehavior("u2", "i3", 3.0, System.currentTimeMillis()));
        behaviors.add(new UserBehavior("u2", "i4", 4.5, System.currentTimeMillis()));
        behaviors.add(new UserBehavior("u3", "i2", 2.5, System.currentTimeMillis()));
        behaviors.add(new UserBehavior("u3", "i4", 4.0, System.currentTimeMillis()));
        behaviors.add(new UserBehavior("u3", "i5", 3.5, System.currentTimeMillis()));
        
        // 2. 数据预处理
        DataPreprocessor preprocessor = new DataPreprocessor();
        Map<String, Map<String, Double>> itemUserMatrix = preprocessor.convertToItemUserMatrix(behaviors);
        Map<String, Map<String, Double>> userItemMatrix = preprocessor.convertToUserItemMatrix(behaviors);
        Map<String, Double> userAvgPrefMap = preprocessor.calculateUserAveragePreference(behaviors);
        
        // 3. 计算物品相似度
        ItemSimilarity itemSimilarity = new ItemSimilarity();
        Map<String, Map<String, Double>> similarityMatrix = itemSimilarity.calculateCosineSimilarity(itemUserMatrix);
        
        // 4. 创建推荐引擎
        ItemBasedRecommender recommender = new ItemBasedRecommender(similarityMatrix, userItemMatrix);
        
        // 5. 为用户生成推荐
        String targetUserId = "u1";
        List<String> recommendations = recommender.recommendItems(targetUserId, 3);
        
        System.out.println("为用户 " + targetUserId + " 推荐的物品:");
        recommendations.forEach(System.out::println);
    }
}

 6. 优化考虑

在实际电商平台中,还需要考虑以下优化:

  1. 数据稀疏性问题

    • 使用降维技术(如SVD)

    • 结合内容信息进行混合推荐

  2. 实时性要求

    • 增量更新相似度矩阵

    • 使用滑动窗口只考虑最近的行为

  3. 冷启动问题

    • 对于新商品,使用基于内容的推荐

    • 对于新用户,使用热门推荐或基于人口统计的推荐

  4. 性能优化

    • 使用缓存存储相似度矩阵

    • 分布式计算处理大规模数据

  5. 业务规则结合

    • 考虑商品类别、价格区间等业务规则

    • 排除已售罄或下架商品 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@百思不得奇解

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值