赞
踩
协同过滤(简称CF)是推荐系统最重要的思想之一。在早期,协同过滤几乎等同于推荐系统。主要的功能是预测和推荐。算法通过对用户历史行为数据的挖掘发现用户的偏好,基于不同的偏好对用户进行群组划分并推荐品味相似的商品。协同过滤推荐算法分为两类,分别是:1、基于用户的协同过滤算法(user-based collaboratIve filtering)(相似的用户可能喜欢相同物品);2、基于物品的协同过滤算法(item-based collaborative filtering)(相似的物品可能被同个用户喜欢)。
皮尔森相关系数是用来衡量变量之间的线性相关性。但是有一个明显的缺陷就是,它只对线性关系敏感。如果关系是非线性的,哪怕两个变量之间是一一对应的关系,皮尔森相关系数也可能接近0.
如果有两个变量:X、Y,最终计算出的相关系数的含义可以有如下理解:
(1)、当相关系数为0时,X和Y两变量无关系。
(2)、当X的值增大(减小),Y值增大(减小),两个变量为正相关,相关系数在0.00与1.00之间。
(3)、当X的值增大(减小),Y值减小(增大),两个变量为负相关,相关系数在-1.00与0.00之间。
通常情况下通过以下取值范围判断变量的相关强度:
相关系数 0.8-1.0 极强相关
0.6-0.8 强相关
0.4-0.6 中等程度相关
0.2-0.4 弱相关
0.0-0.2 极弱相关或无相关
公式一:
公式二:
公式三:
公式四:
Movie电影类:
package com.jun.entity; /** * @author junfeng.lin * @date 2021/3/18 13:37 */ public class Movie implements Comparable<Movie> { public String movieName; public int score; public Movie(String movieName, int score) { this.movieName = movieName; this.score = score; } @Override public String toString() { return "Movie{" + "movieName='" + movieName + '\'' + ", score=" + score + '}'; } @Override public int compareTo(Movie o) { return score > o.score ? -1 : 1; } }
User用户类:
package com.jun.entity; import java.util.ArrayList; import java.util.List; /** * @author junfeng.lin * @date 2021/3/18 13:39 */ public class User { public String username; public List<Movie> movieList = new ArrayList<>(); public User() {} public User(String username) { this.username = username; } public User set(String movieName, int score) { this.movieList.add(new Movie(movieName, score)); return this; } public Movie find(String movieName) { for (Movie movie : movieList) { if (movie.movieName.equals(username)) { return movie; } } return null; } @Override public String toString() { return "User{" + "username='" + username + '\'' + '}'; } }
Recommend逻辑计算类:
package com.jun.Algorithm; import com.jun.entity.Movie; import com.jun.entity.User; import java.util.*; import java.util.stream.Collectors; import java.util.stream.IntStream; /** * @author junfeng.lin * @date 2021/3/18 13:42 */ public class Recommend { /** * 在给定username的情况下,计算其他用户和它的距离并排序 * @param username * @return */ private Map<Double, String> computeNearestNeighbor(String username, List<User> users) { Map<Double, String> distances = new TreeMap<>(); User u1 = new User(username); for (User user:users) { if (username.equals(user.username)) { u1 = user; } } for (int i = 0; i < users.size(); i++) { User u2 = users.get(i); if (!u2.username.equals(username)) { double distance = pearson_dis(u2.movieList, u1.movieList); distances.put(distance, u2.username); } } System.out.println("该用户与其他用户的皮尔森相关系数 -> " + distances); return distances; } /** * 计算2个打分序列间的pearson距离 * 选择公式四进行计算 * @param rating1 * @param rating2 * @return */ private double pearson_dis(List<Movie> rating1, List<Movie> rating2) { int n=rating1.size(); List<Integer> rating1ScoreCollect = rating1.stream().map(A -> A.score).collect(Collectors.toList()); List<Integer> rating2ScoreCollect = rating2.stream().map(A -> A.score).collect(Collectors.toList()); double Ex= rating1ScoreCollect.stream().mapToDouble(x->x).sum(); double Ey= rating2ScoreCollect.stream().mapToDouble(y->y).sum(); double Ex2=rating1ScoreCollect.stream().mapToDouble(x->Math.pow(x,2)).sum(); double Ey2=rating2ScoreCollect.stream().mapToDouble(y->Math.pow(y,2)).sum(); double Exy= IntStream.range(0,n).mapToDouble(i->rating1ScoreCollect.get(i)*rating2ScoreCollect.get(i)).sum(); double numerator=Exy-Ex*Ey/n; double denominator=Math.sqrt((Ex2-Math.pow(Ex,2)/n)*(Ey2-Math.pow(Ey,2)/n)); if (denominator==0) return 0.0; return numerator/denominator; } public List<Movie> recommend(String username, List<User> users) { //找到最近邻 Map<Double, String> distances = computeNearestNeighbor(username, users); String nearest = distances.values().iterator().next(); System.out.println("最近邻 -> " + nearest); //找到最近邻看过,但是我们没看过的电影,计算推荐 User neighborRatings = new User(); for (User user:users) { if (nearest.equals(user.username)) { neighborRatings = user; } } System.out.println("最近邻看过的电影 -> " + neighborRatings.movieList); User userRatings = new User(); for (User user:users) { if (username.equals(user.username)) { userRatings = user; } } System.out.println("用户看过的电影 -> " + userRatings.movieList); //根据自己和邻居的电影计算推荐的电影 List<Movie> recommendationMovies = new ArrayList<>(); for (Movie movie : neighborRatings.movieList) { if (userRatings.find(movie.movieName) == null) { recommendationMovies.add(movie); } } Collections.sort(recommendationMovies); return recommendationMovies; } }
Demo测试类:
package com.jun.Main; import com.jun.Algorithm.Recommend; import com.jun.entity.Movie; import com.jun.entity.User; import java.util.ArrayList; import java.util.List; /** * @author junfeng.lin * @date 2021/3/18 14:07 */ public class Demo { public static void main(String[] args) { //输入用户总量 List<User> users = new ArrayList<>(); users.add(new User("小明") .set("中国合伙人", 50) .set("太平轮", 30) .set("荒野猎人", 45) .set("老炮儿", 50) .set("我的少女时代", 30) .set("肖洛特烦恼", 45) .set("火星救援", 50)); users.add(new User("小红") .set("小时代4", 40) .set("荒野猎人", 30) .set("我的少女时代", 50) .set("肖洛特烦恼", 50) .set("火星救援", 30) .set("后会无期", 30)); users.add(new User("小阳") .set("小时代4", 20) .set("中国合伙人", 50) .set("我的少女时代", 30) .set("老炮儿", 50) .set("肖洛特烦恼", 45) .set("速度与激情7", 50)); users.add(new User("小四") .set("小时代4", 50) .set("中国合伙人", 30) .set("我的少女时代", 40) .set("匆匆那年", 40) .set("速度与激情7", 35) .set("火星救援", 35) .set("后会无期", 45)); users.add(new User("六爷") .set("小时代4", 20) .set("中国合伙人", 40) .set("荒野猎人", 45) .set("老炮儿", 50) .set("我的少女时代", 20)); users.add(new User("小李") .set("荒野猎人", 50) .set("盗梦空间", 50) .set("我的少女时代", 30) .set("速度与激情7", 50) .set("蚁人", 45) .set("老炮儿", 40) .set("后会无期", 35)); users.add(new User("隔壁老王") .set("荒野猎人", 50) .set("中国合伙人", 40) .set("我的少女时代", 10) .set("Phoenix", 50) .set("甄嬛传", 40) .set("The Strokes", 50)); users.add(new User("邻村小芳") .set("小时代4", 40) .set("我的少女时代", 45) .set("匆匆那年", 45) .set("甄嬛传", 25) .set("The Strokes", 30)); Recommend recommend = new Recommend(); List<Movie> recommendationMovies = recommend.recommend("小明", users); System.out.println("-----------------------"); System.out.println("推荐结果如下:"); for (Movie movie : recommendationMovies) { System.out.println("电影:"+movie.movieName+" ,评分:"+movie.score); } } }
运行结果:
参考文章:
1、https://tarzan.blog.csdn.net/article/details/107720624
2、https://blog.csdn.net/cc_want/article/details/85001762?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=1328665.19107.16160427678669067&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。