一、先抄一下
什么事协同过滤算法?
协同过滤算法是一种基于用户行为数据的推荐算法,广泛应用于电商、社交网络、内容推荐等领域。
算法的原理
协同过滤算法主要分为两类:基于用户的协同过滤(User-based CF)和基于物品的协同过滤(Item-based CF)。以下是这两种算法的基本原理:
- 基于用户的协同过滤:找到与目标用户兴趣相似的其他用户,推荐那些相似用户评价高但目标用户尚未评价的物品。
- 基于物品的协同过滤:分析物品之间的相似性,推荐与用户已喜欢物品相似的其他物品。
二、抄完了,到我发挥了
我的原理:我喜欢了商品123,用户A喜欢商品1234,那系统就应该把商品4推荐给我。
如果这时候来了个用户B,用户B喜欢1256商品。那系统就应该把56也推荐给我。
最终推荐给我的应该是456,并且4一定是排在56前面。因为我喜欢的商品,有3个和用户A是一样的,有两个和用户B是一样的。我和A更相似,所以4应该排在前面。
具体代码实现
- 首先新建两个非常简单的类,User和Product
- 然后新建一个订单类,每个订单都包含一个User和一个Product,相当于mysql数据库中存的一条订单,订单包含userId和ProductId,此处就用User和Product代替。
- 第三步开始new女孩子,把她们拿出来给我干活。还有new商品,new订单
这里的订单就相当于我从sql中取出来的所有订单,一个list集合,接下来的任务就是去判断相似度
为了方便学习,我用了中文命名。
上图观察可知: 我买了3个奥特曼,晓晓买了5个奥特曼,张丽买了3个奥特曼,并且我买的3个晓晓都买了,晓晓和我相似度真高,我喜欢晓晓。所以系统应该把我没买,晓晓买了的欧布奥特曼和赛罗奥特曼推荐给我
再看张丽,她比我多买了1个欧布奥特曼,所以和张丽的对比结果,应该给我推荐欧布奥特曼。
欧布奥特曼被推荐了2次,所以最终的推荐结果是,欧布奥特曼在前,赛罗奥特曼在后
上面使我们用眼睛看到的,下面就是具体实现
package com.example.studyonline.controllers;
import java.util.*;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args){
User 我 = new User("我");
User user1 = new User("刘亦菲");
User user2 = new User("朱玲");
User user3 = new User("周佳佳");
User user4 = new User("李蓉");
User user5 = new User("廖雯静");
User user6 = new User("汪齐齐");
User 张丽 = new User("张丽");
User 晓晓 = new User("晓晓");
Product 迪迦奥特曼 = new Product("迪迦奥特曼");
Product 泰罗奥特曼 = new Product("泰罗奥特曼");
Product 赛文奥特曼 = new Product("赛文奥特曼");
Product 欧布奥特曼 = new Product("欧布奥特曼");
Product 赛罗奥特曼 = new Product("赛罗奥特曼");
Order order = new Order(我,迪迦奥特曼);
Order order1 = new Order(我,泰罗奥特曼);
Order order2 = new Order(我,赛文奥特曼);
Order order3 = new Order(晓晓,迪迦奥特曼);
Order order4 = new Order(晓晓,赛文奥特曼);
Order order5 = new Order(晓晓,赛文奥特曼);
Order order6 = new Order(晓晓,欧布奥特曼);
Order order7 = new Order(晓晓,赛罗奥特曼);
Order order8 = new Order(张丽,迪迦奥特曼);
Order order9 = new Order(张丽,泰罗奥特曼);
Order order10 = new Order(张丽,欧布奥特曼);
List<Order> orderList = new ArrayList<>();
orderList.add(order);
orderList.add(order1);
orderList.add(order2);
orderList.add(order3);
orderList.add(order4);
orderList.add(order5);
orderList.add(order6);
orderList.add(order7);
orderList.add(order8);
orderList.add(order9);
orderList.add(order10);
SimpleRecommender2 simpleRecommender2 = new SimpleRecommender2();
for (int i = 0; i < orderList.size(); i++) {
simpleRecommender2.addPurchase(orderList.get(i).getUser(),orderList.get(i).getProduct());
}
// 为我推荐商品
List<Product> recommendations = simpleRecommender2.recommendItems(我, 3);
System.out.println("给我的推荐结果:" + recommendations);
}
public static class SimpleRecommender2 {
// 存储用户-商品购买数据
private Map<User, Set<Product>> userItems = new HashMap<>();
// 添加购买记录
public void addPurchase(User user, Product product) {
Set<Product> strings = userItems.get(user);
if(strings == null){
Set<Product> set = new HashSet<>();
set.add(product);
userItems.put(user,set);
}else{
strings.add(product);
userItems.put(user,strings);
}
// userItems.computeIfAbsent(user, k -> new HashSet<>()).add(item);
}
// 计算Jaccard相似度
private double jaccardSimilarity(Set<Product> set1, Set<Product> set2) {
Set<Product> intersection = new HashSet<>(set1);
intersection.retainAll(set2);
Set<Product> union = new HashSet<>(set1);
union.addAll(set2);
return union.size() == 0 ? 0 : (double) intersection.size() / union.size();
}
// 获取推荐商品(基于最相似用户的购买记录)
public List<Product> recommendItems(User targetUser, int topN) {
Set<Product> targetItems = userItems.getOrDefault(targetUser, Collections.emptySet());
// 存储候选商品及其推荐权重
Map<Product, Double> candidateScores = new HashMap<>();
// 遍历所有用户
for (Map.Entry<User, Set<Product>> entry : userItems.entrySet()) {
User user = entry.getKey();
if (user.equals(targetUser)) continue;
Set<Product> items = entry.getValue();
double similarity = jaccardSimilarity(targetItems, items);
// 只考虑有相似度的用户
if (similarity > 0) {
// 添加该用户有而目标用户没有的商品
items.stream()
.filter(item -> !targetItems.contains(item))
.forEach(item -> candidateScores.merge(item, similarity, Double::sum));
}
}
// 按权重降序排序
return candidateScores.entrySet().stream()
.sorted(Map.Entry.<Product, Double>comparingByValue().reversed())
.limit(topN)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
}
public static class Order{
public User user;
public Product product;
public Order(User user, Product product) {
this.user = user;
this.product = product;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
@Override
public String toString() {
return user.name +"买了"+product.name;
}
}
public static class User{
public String name;
public User(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
public static class Product{
public String name;
public Product(String name) {
this.name = name;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + '\'' +
'}';
}
}
}
程序运行后,最终输出结果:
写着写着代码,突然好想我女朋友,也不知道她吃饭了没,喝水了没,多大了,出生了没。烦人,不写了。我自己学会了就行了。0.0