基于用户的协同过滤算法(JAVA实现)

基于用户的协同过滤算法(JAVA实现)

协同过滤算法

协同过滤(简称CF)是推荐系统最重要的思想之一。在早期,协同过滤几乎等同于推荐系统。主要的功能是预测和推荐。算法通过对用户历史行为数据的挖掘发现用户的偏好,基于不同的偏好对用户进行群组划分并推荐品味相似的商品。协同过滤推荐算法分为两类,分别是:1、基于用户的协同过滤算法(user-based collaboratIve filtering)(相似的用户可能喜欢相同物品);2、基于物品的协同过滤算法(item-based collaborative filtering)(相似的物品可能被同个用户喜欢)。

皮尔森(pearson)相关系数公式

皮尔森相关系数是用来衡量变量之间的线性相关性。但是有一个明显的缺陷就是,它只对线性关系敏感。如果关系是非线性的,哪怕两个变量之间是一一对应的关系,皮尔森相关系数也可能接近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 极弱相关或无相关

公式一:
在这里插入图片描述
公式二:
在这里插入图片描述
公式三:
在这里插入图片描述
公式四:
在这里插入图片描述

Java代码实现

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

  • 54
    点赞
  • 578
    收藏
    觉得还不错? 一键收藏
  • 31
    评论
协同过滤算法是一种推荐系统算法,它通过分析用户的历史行为,比如购买记录、评分记录等,来推荐用户可能感兴趣的产品或内容。其中基于用户点赞的协同过滤算法是一种常见的算法Java实现基于用户点赞的协同过滤算法可以分为以下几个步骤: 1. 数据准备 首先需要准备用户点赞数据,可以从数据库或文件中读取。数据格式应该包含用户ID和点赞的内容ID。 2. 数据处理 将用户点赞数据转换成用户-内容矩阵,矩阵的行表示用户,列表示内容,矩阵中的每个元素表示用户对内容的点赞情况。矩阵中未点赞的位置可以用0或其他值表示。 3. 相似度计算 计算用户之间的相似度,常见的计算方法有余弦相似度和皮尔逊相关系数。可以使用公式或Java库函数计算相似度。 4. 推荐生成 根据相似度矩阵和用户点赞数据,生成推荐结果。可以使用加权平均或其他推荐算法生成推荐结果。 以下是一个简单的Java实现示例: ```java import java.util.HashMap; import java.util.Map; public class CollaborativeFiltering { // 用户点赞数据 private static int[][] userLikes = { {1, 2}, {1, 3, 4}, {2, 3}, {2, 4}, {3, 5}, {4, 5} }; public static void main(String[] args) { // 计算用户-内容矩阵 int[][] userContentMatrix = getUserContentMatrix(userLikes); // 计算用户之间的相似度矩阵 double[][] similarityMatrix = getSimilarityMatrix(userContentMatrix); // 生成推荐结果 Map<Integer, Double> recommendations = getRecommendations(0, userLikes, similarityMatrix); System.out.println(recommendations); } // 将用户点赞数据转换成用户-内容矩阵 private static int[][] getUserContentMatrix(int[][] userLikes) { int maxContentId = 0; for (int[] likes : userLikes) { for (int contentId : likes) { if (contentId > maxContentId) { maxContentId = contentId; } } } int[][] userContentMatrix = new int[userLikes.length][maxContentId]; for (int i = 0; i < userLikes.length; i++) { for (int contentId : userLikes[i]) { userContentMatrix[i][contentId - 1] = 1; } } return userContentMatrix; } // 计算用户之间的相似度矩阵 private static double[][] getSimilarityMatrix(int[][] userContentMatrix) { int numUsers = userContentMatrix.length; double[][] similarityMatrix = new double[numUsers][numUsers]; for (int i = 0; i < numUsers; i++) { for (int j = 0; j < numUsers; j++) { if (i == j) { similarityMatrix[i][j] = 1.0; } else { double dotProduct = 0.0; double norm1 = 0.0; double norm2 = 0.0; for (int k = 0; k < userContentMatrix[i].length; k++) { dotProduct += userContentMatrix[i][k] * userContentMatrix[j][k]; norm1 += Math.pow(userContentMatrix[i][k], 2); norm2 += Math.pow(userContentMatrix[j][k], 2); } similarityMatrix[i][j] = dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2)); } } } return similarityMatrix; } // 生成推荐结果 private static Map<Integer, Double> getRecommendations(int userId, int[][] userLikes, double[][] similarityMatrix) { Map<Integer, Double> recommendations = new HashMap<>(); int[] userLikesArray = userLikes[userId]; for (int contentId = 1; contentId <= userLikesArray.length; contentId++) { if (userLikesArray[contentId - 1] == 0) { double weightedSum = 0.0; double weightSum = 0.0; for (int i = 0; i < userLikes.length; i++) { if (i != userId && userLikes[i][contentId - 1] == 1) { weightedSum += similarityMatrix[userId][i]; weightSum += similarityMatrix[userId][i]; } } if (weightSum > 0.0) { recommendations.put(contentId, weightedSum / weightSum); } } } return recommendations; } } ``` 该示例中,用户点赞数据用二维数组`userLikes`表示,计算用户-内容矩阵用函数`getUserContentMatrix`实现,计算用户之间的相似度矩阵用函数`getSimilarityMatrix`实现,生成推荐结果用函数`getRecommendations`实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值