个性化推荐(基于物品的协同过滤算法) 个性化推荐_视频Demo
- 计算物品之间的相似度
- 根据物品的相似度和用户的历史行为给用户生成推荐列表
设 N(u) 表示喜欢物品u的用户数,| N(u) ⋂ N(u) |表示同时喜欢物品u物品v的用户数,那么物品 u 和 v 的相似度为
以Demo为例,为用户1001推荐商品。
//初始矩阵
for (int i = 0; i < likeLists.size(); i++) {
int pid1 = likeLists.get(i).getPid();
++N[pid1]; //喜欢该id物品的人数加一
for (int j = i + 1; j < likeLists.size(); j++) {
int pid2 = likeLists.get(j).getPid();
++curMatrix[pid1][pid2];
++curMatrix[pid2][pid1]; //对称加一
}
}
//累加所有矩阵, 得到共现矩阵
for (int i = 0; i < products.size(); i++) {
for (int j = 0; j < products.size(); j++) {
int pid1 = products.get(i).getPid(), pid2 = products.get(j).getPid();
comMatrix[pid1][pid2] += curMatrix[pid1][pid2];
comMatrix[pid1][pid2] += curMatrix[pid1][pid2];
}
}
当前用户1001点赞的物品ID为1,由共现矩阵可得Nij。(跳过当前用户1001喜欢得物品1)
根据余弦相似度公式,得Wij。
这里使用了TreeSet重写compare方法实现添加的商品按点赞数排序。
TreeSet<Product> preList = new TreeSet<Product>(new Comparator<Product>() {
//重写compare方法 按相似度Wij排序;当相似度Wij相同时,按点赞数排序
@Override
public int compare(Product o1, Product o2) {
if(o1.getW()!=o2.getW()){
return (int) ((o1.getW()-o2.getW())*100); //返回值为0,表示同一元素
}
else{
//当相似度相同时,比较点赞数
return o1.getCnt()-o2.getCnt();
}
}
}); //预处理的列表
for(Like like: likeLists){
int Nij = 0; //既喜欢i又喜欢j的人数
double Wij; //相似度
Product tmp; //当前的产品
int i = like.getPid();
for(Product product: products){
if(like.getPid() == product.getPid()) continue;
int j = product.getPid();
Nij = comMatrix[i][j];
Wij = (double)Nij/Math.sqrt(N[i]*N[j]); //计算余弦相似度
tmp = productdao.findProductById(product.getPid());
if(Double.isNaN(Wij)) tmp.setW(0);
else tmp.setW(Wij);
if(used[tmp.getPid()]) continue; //已加入推荐列表
if(!Double.isNaN(Wij) && Wij!=0){
preList.add(tmp);
used[tmp.getPid()] = true;
}
}
}
此时推荐的物品列表为4,3,5。
ArrayList<Product> recomLists = new ArrayList<>(); //生成的推荐结果
for(int i = 0; preList.size()>0 && i<5; i++){
recomLists.add(preList.pollLast());
}
此时推荐的物品列表为4,3,5,2,0。
//推荐数量不满5个, 补足喜欢数最高的文章,考虑重复
if(recomLists.size()<5){
recomLists = productdao.findTopNProducts(recomLists);
}