分级加权打分算法java_基于⽤户的协同过滤推荐算法实现原
理及实现代码
基于⽤户的协同过滤推荐算法
实现原理及实现代码
1. 基于⽤户的协同过滤推荐算法实现原理
传统的基于⽤户(User-Based)的协同过滤推荐算法实现原理分四个步骤:
1、根据⽤户历史⾏为信息构建⽤户-项⽬评分矩阵,⽤户历史⾏为信息包括项⽬评分、浏览历史、收藏历史、喜好标签等,本⽂以单⼀的项⽬评分为例,后期介绍其他⾏为信息和混合⾏为信息,⽤户-项⽬评分矩阵如表1所⽰:
项⽬1
项⽬2
项⽬3
⽤户A
1
5
⽤户B
3
4
⽤户C
3
2
表1 ⽤户-项⽬评分矩阵
注:⽤户A对项⽬1的评分是1分,⽤户A对项⽬2没有评分。
2、根据⽤户-项⽬评分矩阵计算⽤户之间的相似度。计算相似度常⽤的⽅法有余弦算法、修正余弦算法、⽪尔森算法等等(后期我们会将相似度算法展开讲解,这⾥以余弦算法为例)。余弦算法公式如图1所⽰:
图1 余弦算法公式
注:表⽰⽤户u的评分集合(也就是矩阵中的⼀⾏评分数据),表⽰⽤户v的评分集合,i表⽰项⽬,表⽰⽤户u对项⽬1的评分乘以⽤户v对项⽬1的评分加上⽤户u对项⽬2的评分乘以⽤户v对项⽬2的评分……先相加再相乘直到最后⼀个项⽬,表⽰⽤户u对项⽬1的评分的平⽅加上⽤户u对项⽬2的评分的平⽅加上……先平⽅再相加直到最后⼀个项⽬然后得到的值取平⽅根,平⽅根乘以⽤户v的平⽅根。
3、根据⽤户之间的相似度得到⽬标⽤户的最近邻居KNN。KNN的筛选常⽤的有两种⽅式,⼀种是设置相似度阀值(给定⼀个相似度的下限,⼤于下限的相似度为最近邻居),⼀种是根据与⽬标⽤户相似度的⾼低来选择前N个最近邻居(本次以前N个为例,后期会详细对⽐讲解两者)。相似度排序可⽤经典冒泡排序法。
4、预测项⽬评分并进⾏推荐。最常⽤的预测公式如图2所⽰:
图2 预测评分公式
注:该公式实际上是相似度和评分的加权平均数。表⽰⽤户u对项⽬i的预测评分,n是最近邻集合,v是任意⼀个最近邻居,表⽰最近邻v和⽬标⽤户u的相似度乘以最近邻v对项⽬i的评分。得到预测评分后按照评分⾼低进⾏降序推荐。
5、结论。以上步骤是最简单,最传统的基于⽤户的协同过滤推荐算法的实现原理,但是在实现过程中还是有很多注意细节。
1. 基于⽤户的协同过滤推荐算法实现代码
本⽂我们介绍两种实现代码,都是java语⾔开发,单机版(本地测试),数据集使⽤movielens的ml-100k,943*1682,80000条数据。
第⼀种,⾃定义实现:
1、项⽬⽬录,如图3所⽰:
图3 项⽬⽬录
2、Application.java⽂件,算法主运⾏⽅法
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
/**
* 协同过滤推荐算法运⾏主⽅法
* @author line
*
*/
public class Application implements Base {
public static void main(String[] args) {
// 输⼊userId,并获取
System.out.println("请输⼊⼀个⽤户Id(1、2、3……943)");
//获取得到输⼊的userId
int userId = Int();
// 从⽂件中读取数据
int[][] user_movie_base = new int[PREFROWCOUNT][COLUMNCOUNT];
//读取⽂件中的数据
user_movie_base = new ReadFile().readFile(BASE);
/
/产⽣相似度矩阵
double[] similarityMatrix = new ProduceSimilarityMatrix().produceSimilarityMatrix(user_movie_base, userId);
// 知道每个⽤户之间的相似度值之后,开始获取每隔相似值对应的userId,然后和相似值关联,再根据相似值排序,即得到相似爱好的userId,然后再输出相似推荐的商品
int[] id = new int[KNEIGHBOUR];//存放K个最近邻userId
//产⽣⼀个临时相似度矩阵变量,是为了相似度排序时和userid对应
double[] tempSimilarity = new double[similarityMatrix.length];
for (int j = 0; j < tempSimilarity.length; j++) {
tempSimilarity[j] = similarityMatrix[j];
}
Arrays.sort(tempSimilarity);//排序,升序
int flag = 0;//临时变量
double[] similarity = new double[KNEIGHBOUR];//保存前K个相似度,从⼤到⼩
for (int m = tempSimilarity.length - 1; m >= tempSimilarity.length - KNEIGHBOUR; m--) {
for(int j = 0; j < similarityMatrix.length; j++) {
if (similarityMatrix[j] == tempSimilarity[m] && similarityMatrix[j] != 0.0){
similarity[flag] = tempSimilarity[m];
id[flag]=j;//保存前K个相似度的userid
flag++;
}
}
}
System.out.println("相似度最近的" + KNEIGHBOUR + "个⽤户是:");
System.out.print("近邻⽤户");
System.out.printf("%25s","相似度");//格式化输出"%25s"是占多少位
System.out.printf("%30sn","推荐产品");
Map<Integer, Double> map = new HashMap<Integer, Double>();//存放每件商品的id和期望值,是键值对关系,即⼀对⼀
for (int i = 0; i < KNEIGHBOUR; i++) {//按照k值得⼤⼩来循环
// 前k个近邻⽤户的推荐产品
int user_id = id[i];//数组id中的userid根据相似度⼤⼩顺序已经排好,从⼤到⼩
int[] items = user_movie_base[user_id];// 获取源数据K个邻近⽤户userid的所有评分
String str = "";
for (int j = 0; j < COLUMNCOUNT; j++) {//循环每件商品,如果相邻⽤户对某件商品的评分不为0,⽽⽬标⽤户的评分为0,该商品就为推荐商品
if ((items[j] != 0) && (user_movie_base[userId - 1][j] == 0)){
str += " " + (j + 1);//将推荐商品的id保存在⼀个字符串中,可以直接输出
//此时,可以通过循环计算某⼀件推荐商品的评分⽤户的相似度期望
//开始计算期望,将相同商品的相似度相加,并保存在map集合中
ainsKey(j + 1)){//如果⼀件商品的值,已经保存在map集合的键中(键是唯⼀的,即不会和其他的数值⼀样),那么键对应的值,就会改变,加上该商品不⽤⽤户的相似度
冒泡排序java代码详解
double d = (j+1);
d+=similarity[i];
map.put(j+1,d);//修改map中的值
}else{
map.put(j+1, similarity[i]);//如果没有保存⼀件商品的id,那么开始保存
}
}
}
System.out.print(id[i] + 1);
System.out.printf("%16st" ,String.format("%.2f",similarity[i]*100)+"%");//输出的同时格式化数据
System.out.println(str);//输出每个⽤户的推荐商品
}
//选择最好的推荐商品,期望加权
//循环map集合的键
Map<Integer,Double> map2 = new HashMap<Integer, Double>(); //保存商品id和加权期望,因为还要对加权期望排序,要和商品id对应
double s1 = 0;
double s2 = 0;
Set<Integer> set = map.keySet();//获取map集合中的所有键,输出是⼀个set集合
for(int key : set){//循环map中的所有键
for (int i = 0; i < KNEIGHBOUR; i++) {
int score = user_movie_base[id[i]][key-1];//map中的键是商品id,i是userid,获取评分
s1+=(key);
s2+=score;
}
map2.put(key, s1/s2);//保存加权期望值,和商品id对应
}
Object[] arr = map2.values().toArray();//获取map2中所有的值,也就是每件商品的加权期望
Arrays.sort(arr);//升序排列,调⽤系统数据包中的函数,⾃动排列数组
set = map2.keySet();//获取商品id
int max=0;//最佳推荐项⽬id
for(int key : set){//循环商品id,根据最⼤的加权期望,到商品id
(key)==arr[arr.length-1]){
max = key;
break;
}
}
System.out.println("最值得推荐的商品是:"+max);
/
/ 误差率
int[][] test = new ReadFile().readFile(TEST); // 462个⽤户的实际评分
double[][] similarityMatrix2 = new ProduceSimilarityMatrix()
.produceSimilarityMatrix(user_movie_base);//获取任意两⾏之间的相似度矩阵
double[][] matrix = new GetScore().getScore(user_movie_base,similarityMatrix2);
double[] mae = new ProduceMAE().produceMAE(matrix, test);
double Mae = 0.0, MAE = 0.0;//平均绝对误差,通过两⼤组数据的相似度矩阵对⽐⽽来
for (int k = 0; k < mae.length; k++) {
Mae += mae[k];
}
MAE = Mae / TESTROWCOUNT;
System.out.println("MAE=:" + MAE);
}
}
3、Base.java⽂件,基础常量接⼝
/**
* 基础静态⽂件数据
* @author line
*
*/
public interface Base {
public static final int KNEIGHBOUR = 10; //number of neighbors最近邻个数
public static final int COLUMNCOUNT = 1682; //number of items 项⽬总数
public static final int PREFROWCOUNT = 943; //number of users in base训练集上的⽤户数⽬public static final int TESTROWCOUNT = 462; //number of users in test测试集上的⽤户数⽬

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。