项目介绍
本期介绍一个基于协同过滤算法的商品推荐系统,主要包括以下功能
(资料图片仅供参考)
后台管理系统功能:
后台登录
获取微信小程序登录的用户信息
配置上架商品的属性,分类,价格
获取用户在小程序端下的订单列表
个人用户配置,账号修改;
微信小程序功能:
用户授权实现微信登陆
首页展示商品轮播图+商品列表
商品详情页,获取商品详细sku
一键加入购物车,直接购买
维护用户的收获地址
订单列表;
全部订单,待收货,确认收货,退货
用户微信授权登录后,根据每个用户收藏的商品数据,根据算法,找到有相似收藏爱好的用户,已推荐相应额商品。为了更方便大家的理解,如下图:
该系统为每一个用户都分配了一个用户账号,用户通过账号的登录可以在系统中查看商品推荐信息及对个人信息进行修改等功能。
系统截图
不止这些,基于协同过滤开发了很多的系统:
现在对着算法的开发的思路还是比较成熟的,更多系统基于推荐算法功能的更新需求,或者系统开发,可以私信评论区留言哦
协同过滤算法简介
协同过滤算法是一种基于用户行为数据的推荐算法,其基本思想是通过分析用户行为数据,找到不同用户之间的相似性,从而预测用户对未知物品的评分或偏好,从而给用户提供个性化推荐。
协同过滤算法分为两种:基于用户的协同过滤和基于物品的协同过滤。
基于用户的协同过滤基于用户的协同过滤算法是通过分析用户的历史行为数据,找到与目标用户行为相似的其他用户,从而推荐目标用户可能感兴趣的物品。
具体步骤如下:
计算用户之间的相似度,如皮尔逊相关系数、余弦相似度等。找到与目标用户相似度最高的K个用户。综合K个用户对某个物品的评分,预测目标用户对该物品的评分或偏好。推荐目标用户评分最高的N个物品。协同过滤算法的优点是可以处理任何类型的物品和用户行为,同时还可以提供高度个性化的推荐。但是,它也存在一些问题,如数据稀疏性、冷启动问题、可扩展性等。因此,在实际应用中需要根据具体情况进行优化和改进。
皮尔森(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代码实现
package com.jun.entity;
/**
* @author 不会写文档的程序员
*/
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;
}
}
package com.jun.entity;
import java.util.ArrayList;
import java.util.List;
/**
* @author 不会写文档的程序员
*/
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逻辑计算类:
/**
* 计算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;
}
}
运行结果:
协同过滤算法的问题分析
目前,协同过滤技术得到了广泛应用。但是随着网站商品信息量和用户人数的不断攀升,网站的结构也越来越复杂,如果你有需要基于协同算法开发的需求,评论区留言呦,我们一起讨论。通过对协同过滤技术以及推荐系统的研究,我们发现协同过滤技术的实现中存在的问题主要有以下几点。
5.1 稀疏性问题
稀疏性问题是推荐系统面临的主要问题。比如在一些大型电子商务购买系统,用户购买过的数量相对网站中商品数量可谓是冰山一角,这就导致了用户评分矩阵的数据非常稀疏,进行相似性计算耗费会很大,也难以找到相邻用户数据集,从而使得推荐系统的推荐质量急剧下降。
5.2 冷启动问题
因为传统的协同过滤推荐是基于用户/物品的相似性计算来得到目标用户的推荐,在一个新的项目首次出现的时候,因为没有用户对它作过评价,因此单纯的协同过滤无法对其进行预测评分和推荐。而且,由于新项目出现早期,用户评价较少,推荐的准确性也比较差。
5.3 可扩展性问题
面对日益增多的数据量,算法的扩展性问题成为制约推荐系统实施的重要因素。识别“最近邻居”算法的计算量随着用户和项的增加而大大增加,对于上百万的数目,通常的算法会遇到严重的扩展性瓶颈问题。
总结
协同过滤作为一种经典的推荐算法种类,在工业界应用广泛,它的优点很多,模型通用性强,不需要太多对应数据领域的专业知识,工程实现简单,效果也不错。这些都是它流行的原因。
当然,协同过滤也有些难以避免的难题,比如令人头疼的“冷启动”问题,我们没有新用户任何数据的时候,无法较好的为新用户推荐物品。同时也没有考虑情景的差异,比如根据用户所在的场景和用户当前的情绪。当然,也无法得到一些小众的独特喜好,这块是基于内容的推荐比较擅长的,小伙伴们欢迎一起学习研究探讨。