目录
简介
协同过滤算法(简称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<Integer,Double>*/public static Map<Integer,Double> computeNeighbor(Integer key, Map<Integer,List<RelateDTO>> map,int type) {Map<Integer,Double> distMap = new TreeMap<>();List<RelateDTO> 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<RelateDTO> xList, List<RelateDTO> yList,int type) {List<Double> xs= Lists.newArrayList();List<Double> 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<Double> xs, List<Double> 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<Integer> userCfRecommend(int userId){List<RelateDTO> data= Sql获取不同用户对不同电影评分关系;// 获取到推荐的电影idList<Integer> 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<Integer>}*/public static List<Integer> recommend(Integer itemId, List<RelateDTO> list) {//按物品分组Map<Integer, List<RelateDTO>> itemMap=list.stream().collect(Collectors.groupingBy(RelateDTO::getItemId));//获取其他物品与当前物品的关系值Map<Integer,Double> 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<Integer> userCfRecommend(int userId){List<RelateDTO> data= Sql获取不同用户对不同电影评分关系;// 获取到推荐的电影idList<Integer> recommendations = ItemCF.recommend(itemId, data);return recommendations ;}}
总结
建议使用基于物品的协同过滤算法,基于物品协同过滤可以预先计算好物品间的相似度,在线查询要比基于用户快的多,且基于物品实际效果质量一般比基于用户高,但这个也不是绝对的,像是抖音这中视频都是最新更新的还是基于用户靠谱。
系数计算要保证,分数值至少每行两个首要条件,其次对比值要多,少的话就没有那么理想结果
------------------------------------------与正文内容无关------------------------------------
如果觉的文章写对各位读者老爷们有帮助的话,麻烦点赞加关注呗!作者在这拜谢了!
混口饭吃了!如果你需要Java 、Python毕设、商务合作、技术交流、就业指导、技术支持度过试用期。请在关注私信我,本人看到一定马上回复!
这是我全部文章所在目录,看看是否有你需要的,如果遇到觉得不对地方请留言,看到后我会查阅进行改正。
A乐神-CSDN博客
关注在文章左上角,作者信息处。