Springboot 实现基于用户和物品的协同过滤算法

 

目录

 

简介

协同过滤算法(简称CF)

算法详解

算法使用

基于用户

基于物品

总结


前言-与正文无关

生活远不止眼前的苦劳与奔波,它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中,我们往往容易陷入工作的漩涡,忘记了停下脚步,感受周围的世界。让我们一起提醒自己,要适时放慢脚步,欣赏生活中的每一道风景,享受与家人朋友的温馨时光,发现那些平凡日子里隐藏的幸福时刻。因为,这些点点滴滴汇聚起来的,才是构成我们丰富多彩生活的本质。希望每个人都能在繁忙的生活中找到自己的快乐之源,不仅仅为了生存而工作,更为了更好的生活而生活。

送你张美图!希望你开心!

简介

协同过滤算法(简称CF)


在早期,协同过滤几乎等同于推荐系统。主要的功能是预测和推荐。协同过滤推荐算法分为两类,分别是:

(英文userCF)

基于用户的协同过滤算法(相似的用户可能喜欢相同物品);这个一般适合推荐新闻和皮皮虾之类的,数据跟人有很大关系,而且信息是每日都是更新的。如果你推荐购物这种,因为一个新建的用户可能购买的商品不足全量商品万分之1,商品数据量大,人对商品购买少,很难找到相似的人;随着用户和物品数量的增加,计算复杂度增加,所以需要这种更适合第二种算法。
(英文itemCF)

基于物品的协同过滤算法(这种方法通过分析物品之间的相似性,根据用户喜欢的物品,,推荐最大相似度其他物品。比如用户喜欢物品A,然后通过算法的出物品C和A的相似度极高,那么用户有可能喜欢物品C)。当然也有缺点:需要足够的用户-物品交互数据来找出物品之间的相似性。

算法详解

如果想知道算法细节可以看我的皮尔森相关系数介绍,这边只是代码级别

推荐系统算法 协同过滤算法详解(二)皮尔森相关系数-CSDN博客

算法使用

下面例子都是基于电影推荐系统做的,向用户推荐喜欢的电影。核心有几个字段,1用户id,2电影id,3是评分。如果你不是电影推荐而是其他,其实代码都一样,逻辑也都大差不差。

核心协同过滤算法类,不管你是基于用户,还是基于商品电影都需要,使用的是皮尔森相关系数

package com.tarzan.recommend.core;

import com.tarzan.recommend.dto.RelateDTO;
import org.assertj.core.util.Lists;

import java.util.*;
import java.util.stream.IntStream;

/**
 * 核心算法
 *
 */
public class CoreMath {



    /**
     * 计算相关系数并排序
     * @param key
     * @param map
     * @return Map
     */
    public static Map computeNeighbor(Integer key, Map>  map,int type) {
        Map distMap = new TreeMap<>();
        List userItems=map.get(key);
        map.forEach((k,v)->{
            //排除此用户
            if(!k.equals(key)){
                //关系系数
                double coefficient = relateDist(v,userItems,type);
                //关系距离
             //   double distance=Math.abs(coefficient);
                distMap.put(k,coefficient);
            }
        });
        return distMap;
    }


    /**
     * 计算两个序列间的相关系数
     *
     * @param xList
     * @param yList
     * @param type 类型0基于用户推荐 1基于物品推荐
     * @return double
     */
    private static double relateDist(List xList, List yList,int type) {
        List xs= Lists.newArrayList();
        List ys= Lists.newArrayList();
        xList.forEach(x->{
            yList.forEach(y->{
                if(type==0){
                    if(x.getItemId().equals(y.getItemId())){
                        xs.add(x.getIndex());
                        ys.add(y.getIndex());
                    }
                }else{
                    if(x.getUseId().equals(y.getUseId())){
                        xs.add(x.getIndex());
                        ys.add(y.getIndex());
                    }
                }
            });
        });
        return getRelate(xs,ys);
    }

    /**
     * 方法描述: 皮尔森(pearson)相关系数计算
     *
     * @param xs x集合
     * @param ys y集合
     */
    public static double getRelate(List xs, List ys){
        int n=xs.size();
        //至少有两个元素
        if (n<2) {
            return 0D;
        }
        double Ex= xs.stream().mapToDouble(x->x).sum();
        double Ey=ys.stream().mapToDouble(y->y).sum();
        double Ex2=xs.stream().mapToDouble(x->Math.pow(x,2)).sum();
        double Ey2=ys.stream().mapToDouble(y->Math.pow(y,2)).sum();
        double Exy= IntStream.range(0,n).mapToDouble(i->xs.get(i)*ys.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 0D;
        }
        return numerator/denominator;
    }

}

实体类

package com.tarzan.recommend.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 关系数据
 *
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RelateDTO {
    /** 用户id */
    private Integer useId;
    /** 电影id */
    private Integer itemId;
    /** 评分 */
    private Double index;


}

基于用户

入参是你要给推荐具体电影的当前用户id,

package com.tarzan.recommend.service;

import com.tarzan.recommend.core.ItemCF;
import com.tarzan.recommend.core.UserCF;
import com.tarzan.recommend.dto.ItemDTO;
import com.tarzan.recommend.dto.RelateDTO;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 推荐服务
 *
 */
public class Recommend{

    /**
     * 方法描述: 猜你喜欢
     *
     * @param userId 用户id
     */
    public static List  userCfRecommend(int userId){
        List data= Sql获取不同用户对不同电影评分关系;
        // 获取到推荐的电影id
        List recommendations = UserCF.recommend(userId, data);
        return recommendations ;
    }


}
package com.tarzan.recommend.core;

import com.tarzan.recommend.dto.RelateDTO;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 核心算法
 *
 * @since JDK1.8
 */
public class ItemCF {

    /**
     * 方法描述: 推荐电影id列表
     *
     * @param itemId 当前电影id
     * @param list 用户电影评分数据
     * @return {@link List}
     */
    public static List recommend(Integer itemId, List list) {
        //按物品分组
        Map>  itemMap=list.stream().collect(Collectors.groupingBy(RelateDTO::getItemId));
        //获取其他物品与当前物品的关系值
        Map  itemDisMap = CoreMath.computeNeighbor(itemId, itemMap,1);
        //获取关系最近物品
        double maxValue=Collections.max(itemDisMap.values());
        return itemDisMap.entrySet().stream().filter(e->e.getValue()==maxValue).map(Map.Entry::getKey).collect(Collectors.toList());
    }


}

 

基于物品

入参是当前用户曾经评过高分的电影id,以此通过算法推荐和此电影相似度高的电影

package com.tarzan.recommend.service;

import com.tarzan.recommend.core.ItemCF;
import com.tarzan.recommend.core.UserCF;
import com.tarzan.recommend.dto.ItemDTO;
import com.tarzan.recommend.dto.RelateDTO;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 推荐服务
 *
 */
public class Recommend{

    /**
     * 方法描述: 猜你喜欢
     *
     * @param itemId 电影id
     */
    public static List  userCfRecommend(int userId){
        List data= Sql获取不同用户对不同电影评分关系;
        // 获取到推荐的电影id
        List recommendations = ItemCF.recommend(itemId, data);
        return recommendations ;
    }


}

总结

建议使用基于物品的协同过滤算法,基于物品协同过滤可以预先计算好物品间的相似度,在线查询要比基于用户快的多,且基于物品实际效果质量一般比基于用户高,但这个也不是绝对的,像是抖音这中视频都是最新更新的还是基于用户靠谱。

系数计算要保证,分数值至少每行两个首要条件,其次对比值要多,少的话就没有那么理想结果

------------------------------------------与正文内容无关------------------------------------
如果觉的文章写对各位读者老爷们有帮助的话,麻烦点赞加关注呗!作者在这拜谢了!

混口饭吃了!如果你需要Java 、Python毕设、商务合作、技术交流、就业指导、技术支持度过试用期。请在关注私信我,本人看到一定马上回复!

这是我全部文章所在目录,看看是否有你需要的,如果遇到觉得不对地方请留言,看到后我会查阅进行改正。

A乐神-CSDN博客

关注在文章左上角,作者信息处。

Springboot 实现基于用户和物品的协同过滤算法_第1张图片

你可能感兴趣的:(java框架,spring,boot,算法,后端)