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