算法说明
综合用户浏览(权重1)和购买记录(权重2)
进行归一化处理,消除品类数量差异
示例:购买电子产品的权重是浏览书籍的2倍
价格区间计算:
基于用户历史行为计算平均价格和标准差
使用高斯函数计算价格相似度,考虑价格分布的集中趋势
推荐评分:
综合品类匹配度(70%)和价格匹配度(30%)
使用流式处理进行高效计算和排序
优化方向:
冷启动问题:新用户无历史记录时,可结合热门商品推荐
实时更新:使用滑动窗口机制处理用户行为的时效性
深度学习:对于大规模数据可升级为神经网络模型
多维度特征:加入品牌、用户画像等更多特征
在计算商品相似度时,对于每个候选商品:
类别得分:该商品的每个类别的权重之和,根据用户偏好中的类别权重。例如,商品有类别A和B,用户偏好中A的权重是2,B的权重是3,那么得分是2+3=5。或者可能需要归一化处理,比如用户的总权重是某个值,然后计算相似度。
或者,使用余弦相似度,将用户偏好向量和商品向量表示为TF-IDF类型的权重,然后计算点积。
例如,将所有可能的类别收集为一个词汇表,然后用户偏好向量是每个类别的出现次数(或TF-IDF值),商品向量是该商品是否属于每个类别(0或1)。然后计算余弦相似度。
价格相似度可以单独计算,比如使用高斯核函数:exp(- (price_diff)^2 / (2 * sigma^2)),其中sigma是标准差,根据用户购买记录中的价格计算得出。
然后,总相似度是类别相似度乘以0.7 + 价格相似度乘以0.3,或者其他权重组合。
在代码中,可能需要先遍历所有用户的购买和浏览记录,统计类别出现的次数,计算每个类别的权重。购买次数和浏览次数可能需要不同的权重,比如购买一次算2分,浏览一次算1分。
然后,对于每个候选商品,计算其类别得分,即该商品所属类别在用户偏好中的权重之和。然后归一化这个得分,例如除以最大可能的得分,使其在0到1之间。
价格方面,计算该商品的价格与用户平均价格的差异,然后转化为相似度得分。例如,如果用户平均价格是100元,商品价格是120元,差异是20元,价格相似度可以是max(0, 1 - (20 / 100)) = 0.8,如果差异超过100,则得分为0。
或者,价格区间可以设定为用户购买记录中的最低和最高价格,然后如果商品价格在此区间内,得1分,否则按距离扣分。
处理冷启动的常见方法包括:
1. 推荐热门商品:当用户没有历史记录时,推荐销量或浏览量高的商品。
2. 基于人口统计学的推荐:比如根据用户的年龄、性别等信息,但当前User类没有这些属性,可能需要扩展。
3. 随机推荐:但可能不够精准。
4. 混合推荐:结合热门和随机推荐。
由于当前代码中的User类没有其他属性,可能采用推荐热门商品作为冷启动策略。需要修改推荐方法,当检测到用户没有历史记录时,切换到热门商品推荐。
新增功能说明:
冷启动用户判断:
通过isColdStartUser()方法检测用户是否没有浏览和购买记录
自动切换推荐策略
全局特征分析:
getGlobalCategoryPreferences():分析当前候选商品的品类分布
getGlobalPriceRange():计算全体候选商品的价格分布
混合推荐策略:
优先推荐高频品类商品(平台热门商品)
结合价格中位数附近商品(大众接受度高的价格区间)
权重调整为品类60% + 价格40%
动态适应机制:
根据当前可推荐商品实时计算特征
自动适应商品上下架变化
public class ProductRecommender {
private static final double CATEGORY_WEIGHT = 0.7;
private static final double PRICE_WEIGHT = 0.3;
private static final double PRICE_RANGE_FACTOR = 0.3;
private static final double COLD_START_CATEGORY_WEIGHT = 0.6;
private static final double COLD_START_PRICE_WEIGHT = 0.4;
private final Map<UserShopGoods, Map<String, Double>> userCategoryCache = new WeakHashMap<>();
private final Map<UserShopGoods, double[]> userPriceRangeCache = new WeakHashMap<>();
private final Map<List<ShopGoodsItem>, Map<String, Double>> globalCategoryCache = new WeakHashMap<>();
private final Map<List<ShopGoodsItem>, double[]> globalPriceRangeCache = new WeakHashMap<>();
private Map<String, Double> getCategoryPreferences(UserShopGoods user) {
return userCategoryCache.computeIfAbsent(user, k -> computeCategoryPreferences(user));
}
private double[] getPriceRange(UserShopGoods user) {
return userPriceRangeCache.computeIfAbsent(user, k -> computePriceRange(user));
}
private Map<String, Double> getGlobalCategoryPreferences(List<ShopGoodsItem> items) {
return globalCategoryCache.computeIfAbsent(items, k -> computeGlobalCategoryPreferences(items));
}
private double[] getGlobalPriceRange(List<ShopGoodsItem> items) {
return globalPriceRangeCache.computeIfAbsent(items, k -> computeGlobalPriceRange(items));
}
public List<ShopGoodsItem> recommend(UserShopGoods user, List<ShopGoodsItem> allItems, int topN) {
Set<ShopGoodsItem> purchasedItems = new HashSet<>(user.getPurchaseHistory());
List<ShopGoodsItem> candidates = allItems.stream()
.filter(item