1.功能介绍
根据用户购买过的物品进行推荐
1.查找推荐用户购买过的物品
2.查找所有用户购买过的物品
3.找到同推荐用户购买过相同物品的用户和物品
4.计算用户之间的相似度【余弦相似性】
5.计算相似用户的物品推荐度
6.取相似度最高的前三个物品进行推荐(推荐物品数量可自定义)
2.代码实现
数据说明
1.测试数据userList总共有四条,分别为:
[
{
"userId":15
},
{
"userId":30
},
{
"userId":31
},
{
"userId":32
}
]
2.测试数据orderList总共有七条,分别为:
[
{
"orderId":"1",
"flightId":"16",
"userId":15
},
{
"orderId":"2",
"flightId":"3",
"userId":15
},
{
"orderId":"3",
"flightId":"16",
"userId":30
},
{
"orderId":"4",
"flightId":"1",
"userId":30
},
{
"orderId":"5",
"flightId":"9",
"userId":31
},
{
"orderId":"6",
"flightId":"13",
"userId":31
},
{
"orderId":"7",
"flightId":"16",
"userId":31
}
]
实现类
/**
* 推荐算法--基于用户的协同过滤算法
*
* @param userId 要推荐的用户ID
* @return 推荐的商品集合
*/
public List<Integer> recommendFlightId(Integer userId) {
System.out.println("推荐用户ID:" + userId);
// 查询推荐用户信息
// User uid = userService.getUserById(userId);
// 查询所有用户信息
List<User> userList = userService.listUser();
Integer N = userList.size();
System.out.println("用户数量:" + N);
// 建立用户稀疏矩阵,用于用户相似度计算【相似度矩阵】
Long[][] sparseMatrix = new Long[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++)
sparseMatrix[i][j] = (long) 0;
}
// 存储每一个用户对应的不同物品总数 userId:total
Map<Integer, Integer> userItemLength = new HashMap<>();
// 建立物品到用户的倒排表 物品ID:购买过该物品的所有用户
Map<Integer, Set<Integer>> itemUserCollection = new HashMap<>();
// 辅助存储物品集合 所有被购买过的物品ID
Set<Integer> items = new HashSet<>();
// 辅助存储每一个用户的用户ID映射:user->userId
Map<Integer, Integer> userIdMap = new HashMap<>();
// 辅助存储每一个ID对应的用户映射:id->userId
Map<Integer, Integer> idUser = new HashMap<>();
// 依次处理N个用户
for (int i = 0; i < N; i++) {
Integer id = userList.get(i).getUserId();
// 用户的所有订单
List<Order> orderList = orderService.getByUserId(id);
userItemLength.put(id, orderList.size());
// 用户ID与稀疏矩阵建立对应关系
userIdMap.put(id, i);
idUser.put(i, id);
// 建立物品--用户倒排表
for (int j = 0; j < orderList.size(); j++) {
// 订单中的物品(推荐的物品ID)
Integer flightId = orderList.get(j).getFlightId();
// 如果已经包含对应的物品--用户映射,直接添加对应的用户
if (items.contains(flightId)) {
itemUserCollection.get(flightId).add(id);
} else {
// 否则创建对应物品--用户集合映射
items.add(flightId);
// 创建物品--用户倒排关系
itemUserCollection.put(flightId, new HashSet<Integer>());
itemUserCollection.get(flightId).add(id);
}
}
}
// 输出倒排关系表
System.out.println("输出倒排关系表:\n" + itemUserCollection);
// 计算相似度矩阵【稀疏】
Set<Map.Entry<Integer, Set<Integer>>> entrySet = itemUserCollection.entrySet();
Iterator<Map.Entry<Integer, Set<Integer>>> iterator = entrySet.iterator();
while (iterator.hasNext()) {
Set<Integer> commonUsers = iterator.next().getValue();
for (Integer user_u : commonUsers) {
for (Integer user_v : commonUsers) {
if (user_u == user_v) {
continue;
}
//计算用户u与用户v都有正反馈的物品总数
sparseMatrix[userIdMap.get(user_u)][userIdMap.get(user_v)] += 1;
}
}
}
// 计算用户之间的相似度【余弦相似性】
System.out.println("用户之间的相似度:");
Integer recommendUserId = userIdMap.get(userId);
for (int j = 0; j < sparseMatrix.length; j++) {
if (j != recommendUserId) {
System.out.println(idUser.get(recommendUserId) + "--" + idUser.get(j) + "相似度:"
+ sparseMatrix[recommendUserId][j] / Math.sqrt(userItemLength.get(idUser.get(recommendUserId)) * userItemLength.get(idUser.get(j))));
}
}
// 计算指定用户recommendUser的物品推荐度
Map<Integer, Double> itemRecommendDegree = new HashMap<>();//flightId->推荐度
for (Integer item : items) {
//遍历每一件物品
//得到购买当前物品的所有用户集合
Set<Integer> users = itemUserCollection.get(item);
//如果被推荐用户没有购买当前物品,则进行推荐度计算
if (!users.contains(userId)) {
double RecommendDegree = 0.0;
for (Integer user : users) {
//推荐度计算
RecommendDegree += sparseMatrix[userIdMap.get(userId)][userIdMap.get(user)] / Math.sqrt(userItemLength.get(userId) * userItemLength.get(user));
}
itemRecommendDegree.put(item, RecommendDegree);
}
}
System.out.println("flightIdID,推荐度:\n" + itemRecommendDegree);
//取最大的3个(可自定义)
if (itemRecommendDegree.size() < 3) {
List<Integer> list = itemRecommendDegree.entrySet().stream()
.sorted((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()))
.map(entry -> entry.getKey()).collect(Collectors.toList());
System.out.println("推荐的物品Id:" + list);
return list;
} else {
List<Integer> list = itemRecommendDegree.entrySet().stream()
.sorted((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()))
.map(entry -> entry.getKey()).collect(Collectors.toList())
.subList(0, 3);
System.out.println("推荐的物品Id:" + list);
return list;
}
}
推荐结果
这是传入userId:15的推荐结果,最后的1,9,13为推荐的物品ID
推荐用户ID:15
用户数量:4
输出倒排关系表:
{
16=[30, 15, 31], 1=[30], 3=[15], 9=[31], 13=[31]}
用户之间的相似度:
15--30相似度:0.5
15--31相似度:0.4082482904638631
15--32相似度:NaN
flightIdID,推荐度:
{
1=0.5, 9=0.4082482904638631, 13=0.4082482904638631}
推荐的物品Id:[1, 9, 13]