精华内容
下载资源
问答
  • 协同过滤推荐算法(java原生JDK实现-附源码地址)

    万次阅读 多人点赞 2017-12-02 13:55:28
    协同过滤推荐算法(java原生JDK实现-附源码地址) 一、项目需求 1.需求链接 https://tianchi.aliyun.com/getStart/information.htm?raceId=231522 2.需求内容 竞赛题目 在真实的业务场景下,我们往往需要对所有商品...

    一、项目需求

    1.    需求链接

    https://tianchi.aliyun.com/getStart/information.htm?raceId=231522

    2.    需求内容

    竞赛题目

    在真实的业务场景下,我们往往需要对所有商品的一个子集构建个性化推荐模型。在完成这件任务的过程中,我们不仅需要利用用户在这个商品子集上的行为数据,往往还需要利用更丰富的用户行为数据。定义如下的符号:
    U——用户集合
    I——商品全集
    P——商品子集, I
    D——
    用户对商品全集的行为数据集合
    那么我们的目标是利用D来构造U中用户对P中商品的推荐模型。

    数据说明

    本场比赛提供20000用户的完整行为数据以及百万级的商品信息。竞赛数据包含两个部分。

    第一部分是用户在商品全集上的移动端行为数据(D,表名为tianchi_fresh_comp_train_user_2w,包含如下字段:

    字段

    字段说明

    提取说明

    user_id

    用户标识

    抽样&字段脱敏

    item_id

    商品标识

    字段脱敏

    behavior_type

    用户对商品的行为类型

    包括浏览、收藏、加购物车、购买,对应取值分别是1234

    user_geohash

    用户位置的空间标识,可以为空

    由经纬度通过保密的算法生成

    item_category

    商品分类标识

    字段脱敏

    time

    行为时间

    精确到小时级别

    第二个部分是商品子集(P,表名为tianchi_fresh_comp_train_item_2w,包含如下字段: 

     字段

    字段说明

    提取说明

     item_id

     商品标识

     抽样&字段脱敏

     item_ geohash

     商品位置的空间标识,可以为空

     由经纬度通过保密的算法生成

     item_category 

     商品分类标识

     字段脱敏

    训练数据包含了抽样出来的一定量用户在一个月时间(11.18~12.18)之内的移动端行为数据(D),评分数据是这些用户在这个一个月之后的一天(12.19)对商品子集(P)的购买数据。参赛者要使用训练数据建立推荐模型,并输出用户在接下来一天对商品子集购买行为的预测结果。 

    评分数据格式
    具体计算公式如下:参赛者完成用户对商品子集的购买预测之后,需要将结果放入指定格式的数据表(非分区表)中,要求结果表名为:tianchi_mobile_recommendation_predict.csv,且以utf-8格式编码;包含user_iditem_id两列(均为string类型),要求去除重复。例如:

     

    评估指标

    比赛采用经典的精确度(precision)、召回率(recall)F1值作为评估指标。具体计算公式如下:

     

    其中PredictionSet为算法预测的购买数据集合,ReferenceSet为真实的答案购买数据集合。我们以F1值作为最终的唯一评测标准。

    二、协同过滤推荐算法原理及实现流程

    1.    基于用户的协同过滤推荐算法

     

    基于用户的协同过滤推荐算法通过寻找与目标用户具有相似评分的邻居用户,通过查找邻居用户喜欢的项目,推测目标用户也具有相同的喜好。基于用户的协同过滤推荐算法基本思想是:根据用户-项目评分矩阵查找当前用户的最近邻居,利用最近邻居的评分来预测当前用户对项目的预测值,将评分最高的N个项目推荐给用户,其中的项目可理解为系统处理的商品。其算法流程图如下图1所示。

    图1基于用户的协同过滤推荐算法流程

    基于用户的协同过滤推荐算法流程为:

    1).构建用户项目评分矩阵

    R={ , …… },T:m×n的用户评分矩阵,其中r={ , ,……, }为用户 的评分向量, 代表用户 对项目 的评分。

    2).计算用户相似度

    基于用户的协同过滤推荐算法,需查找与目标用户相似的用户。衡量用户之间的相似性需要计算每个用户的评分与其他用户评分的相似度,即评分矩阵中的用户评分记录。每个用户对项目的评分可以看作是一个n维的评分向量。使用评分向量计算目标用户 与其他用户 之间的相似度sim(i,j),通常计算用户相似度的方法有三种:余弦相似度、修正的余弦相似度和皮尔森相关系数。

    3).构建最近邻居集

    最近邻居集Neighor(u)中包含的是与目标用户具有相同爱好的其他用户。为选取邻居用户,我们首先计算目标用户u与其他用户v的相似度sim(u,v),再选择相似度最大的k个用户。用户相似度可理解为用户之间的信任值或推荐权重。通常,sim(u,v)∈[1,1]。用户相似度为1表示两个用户互相的推荐权重很大。如果为-1,表示两个用户的由于兴趣相差很大,因此互相的推荐权重很小。

    4).预测评分计算

    用户a 对项目i的预测评分p(a,i)为邻居用户对该项目评分的加权评分值。显然,不同用户对于目标用户的影响程度不同,所以在计算预测评分时,不同用户有不同的权重。计算时,我们选择用户相似度作为用户的权重因子,计算公式如下:

       

          基于用户的协同过滤推荐算法实现步骤为:

    1).实时统计user对item的打分,从而生成user-item表(即构建用户-项目评分矩阵);

    2).计算各个user之间的相似度,从而生成user-user的得分表,并进行排序;

    3).对每一user的item集合排序;

    4).针对预推荐的user,在user-user的得分表中选择与该用户最相似的N个用户,并在user-item表中选择这N个用户中已排序好的item集合中的topM;

    5).此时的N*M个商品即为该用户推荐的商品集。

    2.    基于项目的协同过滤推荐算法

    基于项目的协同过滤推荐算法依据用户-项目评分矩阵通过计算项目之间的评分相似性来衡量项目评分相似性,找到与目标项目最相似的n个项目作为最近邻居集。然后通过对目标项目的相似邻居赋予一定的权重来预测当前项目的评分,再将得到的最终预测评分按序排列,将评分最高的N个项目推荐给当前用户,其中的项目可理解为系统处理的商品。其算法流程如下图2所示。

    图2基于项目的协同过滤推荐算法流程

    基于项目的协同过滤推荐算法流程为:

    首先,读取目标用户的评分记录集合 ;然后计算项目i与 中其他项目的相似度,选取k个最近邻居;根据评分相似度计算公式计算候选集中所有项目的预测评分;最后选取预测评分最高的N个项目推荐给用户。

    基于项目的协同过滤推荐算法预测评分与其他用户评分的加权评分值相关,不同的历史评分项目与当前项目i的相关度有差异,所以在进行计算时,不同的项目有不同的权重。评分预测函数p(u,i),以项目相似度作为项目的权重因子,得到的评分公式如下:

    基于项目的协同过滤推荐算法实现步骤为:

    1).实时统计user对item的打分,从而生成user-item表(即构建用户-项目评分矩阵);

    2).计算各个item之间的相似度,从而生成item-item的得分表,并进行排序;

    3).对每一user的item集合排序;

    4).针对预推荐的user,在该用户已选择的item集合中,根据item-item表选择与已选item最相似的N个item;

    5).此时的N个商品即为该用户推荐的商品集。

    3.    基于用户的协同过滤推荐算法与基于项目的协同过滤推荐算法比较

    基于用户的协同过滤推荐算法:

    可以帮助用户发现新的商品,但需要较复杂的在线计算,需要处理新用户的问题。

    基于项目的协同过滤推荐算法:

    准确性好,表现稳定可控,便于离线计算,但推荐结果的多样性会差一些,一般不会带给用户惊喜性。

    三、    项目实现

    针对移动推荐,我们选择使用基于用户的协同过滤推荐算法来进行实现。

    1.    数据模型及其实体类

    用户行为数据:(user.csv)

    user_id,item_id,behavior_type,user_geohash,item_category,time

    10001082,285259775,1,97lk14c,4076,2014-12-08 18

    10001082,4368907,1,,5503,2014-12-12 12

    10001082,4368907,1,,5503,2014-12-12 12

    10001082,53616768,1,,9762,2014-12-02 15

    10001082,151466952,1,,5232,2014-12-12 11

    10001082,53616768,4,,9762,2014-12-02 15

    10001082,290088061,1,,5503,2014-12-12 12

    10001082,298397524,1,,10894,2014-12-12 12

    10001082,32104252,1,,6513,2014-12-12 12

    10001082,323339743,1,,10894,2014-12-1212

    商品信息:(item.csv)

    item_id,item_geohash,item_category

    100002303,,3368

    100003592,,7995

    100006838,,12630

    100008089,,7791

    100012750,,9614

    100014072,,1032

    100014463,,9023

    100019387,,3064

    100023812,,6700
    package entity;
    
    public class Item implements Comparable<Item> {
    	private String itemId;
    	private String itemGeoHash;
    	private String itemCategory;
    	private double weight;
    	public String getItemId() {
    		return itemId;
    	}
    	public void setItemId(String itemId) {
    		this.itemId = itemId;
    	}
    	public String getItemGeoHash() {
    		return itemGeoHash;
    	}
    	public void setItemGeoHash(String itemGeoHash) {
    		this.itemGeoHash = itemGeoHash;
    	}
    	public String getItemCategory() {
    		return itemCategory;
    	}
    	public void setItemCategory(String itemCategory) {
    		this.itemCategory = itemCategory;
    	}
    	public double getWeight() {
    		return weight;
    	}
    	public void setWeight(double weight) {
    		this.weight = weight;
    	}
    	@Override
    	public String toString() {
    		return "Item [itemId=" + itemId + ", itemGeoHash=" + itemGeoHash
    				+ ", itemCategory=" + itemCategory + ", weight=" + weight + "]";
    	}
    	@Override
    	public int compareTo(Item o) {
    		return (int) (-1 * (this.weight - o.weight));
    	}
    	
    	
    }
    
    package entity;
    
    public class Score implements Comparable<Score> {
    	private String userId;      // 用户标识
    	private String itemId;      // 商品标识
    	private double score;
    	public String getUserId() {
    		return userId;
    	}
    	public void setUserId(String userId) {
    		this.userId = userId;
    	}
    	public String getItemId() {
    		return itemId;
    	}
    	public void setItemId(String itemId) {
    		this.itemId = itemId;
    	}
    	public double getScore() {
    		return score;
    	}
    	public void setScore(double score) {
    		this.score = score;
    	}
    	@Override
    	public String toString() {
    		return "Score [userId=" + userId + ", itemId=" + itemId + ", score="
    				+ score + "]";
    	}
    	@Override
    	public int compareTo(Score o) {
    		if ((this.score - o.score) < 0) {
    			return 1;
    		}else if ((this.score - o.score) > 0) {
    			return -1;
    		}else {
    			return 0;
    		}
    	}
    	@Override
    	public int hashCode() {
    		final int prime = 31;
    		int result = 1;
    		result = prime * result + ((itemId == null) ? 0 : itemId.hashCode());
    		long temp;
    		temp = Double.doubleToLongBits(score);
    		result = prime * result + (int) (temp ^ (temp >>> 32));
    		result = prime * result + ((userId == null) ? 0 : userId.hashCode());
    		return result;
    	}
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		Score other = (Score) obj;
    		if (itemId == null) {
    			if (other.itemId != null)
    				return false;
    		} else if (!itemId.equals(other.itemId))
    			return false;
    		if (Double.doubleToLongBits(score) != Double
    				.doubleToLongBits(other.score))
    			return false;
    		if (userId == null) {
    			if (other.userId != null)
    				return false;
    		} else if (!userId.equals(other.userId))
    			return false;
    		return true;
    	}
    	
    }
    
    package entity;
    
    public class User implements Comparable<User> {
    	private String userId;      // 用户标识
    	private String itemId;      // 商品标识
    	private double behaviorType;   // 用户对商品的行为类型,可以为空,包括浏览、收藏、加购物车、购买,对应取值分别是1、2、3、4.
    	private String userGeoHash; // 用户位置的空间标识
    	private String itemCategory;// 商品分类标识
    	private String time;        // 行为时间
    	private int count;
    	private double weight;      // 权重
    	public String getUserId() {
    		return userId;
    	}
    	public void setUserId(String userId) {
    		this.userId = userId;
    	}
    	public String getItemId() {
    		return itemId;
    	}
    	public void setItemId(String itemId) {
    		this.itemId = itemId;
    	}
    	public double getBehaviorType() {
    		return behaviorType;
    	}
    	public void setBehaviorType(double behaviorType) {
    		this.behaviorType = behaviorType;
    	}
    	
    	public String getUserGeoHash() {
    		return userGeoHash;
    	}
    	public void setUserGeoHash(String userGeoHash) {
    		this.userGeoHash = userGeoHash;
    	}
    	public String getItemCategory() {
    		return itemCategory;
    	}
    	public void setItemCategory(String itemCategory) {
    		this.itemCategory = itemCategory;
    	}
    	public String getTime() {
    		return time;
    	}
    	public void setTime(String time) {
    		this.time = time;
    	}
    	
    	
    	
    	@Override
    	public String toString() {
    		return "User [userId=" + userId + ", itemId=" + itemId
    				+ ", behaviorType=" + behaviorType + ", count=" + count + "]";
    	}
    	
    	public int getCount() {
    		return count;
    	}
    	public void setCount(int count) {
    		this.count = count;
    	}
    	public double getWeight() {
    		return weight;
    	}
    	public void setWeight(double weight) {
    		this.weight = weight;
    	}
    	@Override
    	public int compareTo(User o) {
    		return (int)((-1) * (this.weight - o.weight));
    	}
    	
    }
    
    

    2.    工具类

    文件处理工具:

    package util;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.PrintStream;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.LinkedHashMap;
    import java.util.LinkedHashSet;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import entity.Item;
    import entity.Score;
    import entity.User;
    
    
    public class FileTool {
    	
    	public static FileReader fr=null;
    	public static BufferedReader br=null;
    	public static String line=null;
    	
    	public static FileOutputStream fos1 = null,fos2 = null,fos3 = null;
    	public static PrintStream ps1 = null,ps2 = null,ps3 = null;
    	
    	public static int count = 0;
    	
    	/** 
    	 * 初始化写文件器(单一指针)
    	 * */
    	public static void initWriter1(String writePath) {
    		try {
    			fos1 = new FileOutputStream(writePath);
    			ps1 = new PrintStream(fos1);
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    	/** 
    	 * 关闭文件器(单一指针)
    	 * */
    	public static void closeReader() {
    		try {
    			br.close();
    			fr.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	/** 
    	 * 关闭文件器(单一指针)
    	 * */
    	public static void closeWriter1() {
    		try {
    			ps1.close();
    			fos1.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	/** 
    	 * 初始化写文件器(双指针)
    	 * */
    	public static void initWriter2(String writePath1,String writePath2) {
    		try {
    			fos1 = new FileOutputStream(writePath1);
    			ps1 = new PrintStream(fos1);
    			fos2 = new FileOutputStream(writePath2);
    			ps2 = new PrintStream(fos2);
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    	/** 
    	 * 关闭文件器(双指针)
    	 * */
    	public static void closeWriter2() {
    		try {
    			ps1.close();
    			fos1.close();
    			ps2.close();
    			fos2.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	/** 
    	 * 初始化写文件器(三指针)
    	 * */
    	public static void initWriter3(String writePath1,String writePath2,String writePath3) {
    		try {
    			fos1 = new FileOutputStream(writePath1);
    			ps1 = new PrintStream(fos1);
    			fos2 = new FileOutputStream(writePath2);
    			ps2 = new PrintStream(fos2);
    			fos3 = new FileOutputStream(writePath3);
    			ps3 = new PrintStream(fos3);
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    	/** 
    	 * 关闭文件器(三指针)
    	 * */
    	public static void closeWriter3() {
    		try {
    			ps1.close();
    			fos1.close();
    			ps2.close();
    			fos2.close();
    			ps3.close();
    			fos3.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	public static List readFileOne(String path, boolean isTitle, String token, String pattern, String process) throws Exception {
    		List<Object> ret = new ArrayList<Object>();
    		
    		fr = new FileReader(path);
    		br = new BufferedReader(fr);
    		int count = 0,i = 0;
    		
    		if (isTitle) {
    			line = br.readLine();
    			count++;
    		}
    		
    		while((line = br.readLine()) != null){
    			String[] strArr = line.split(token);
    			switch (pattern) {
    			case "item":
    				ret.add(ParseTool.parseItem(strArr));
    				break;
    			case "user":
    				ret.add(ParseTool.parseUser(strArr, process));
    				break;
    			default:
    				ret.add(line);
    				break;
    			}
    			count++;
    			if (count/100000 == 1) {
    				i++;
    				System.out.println(100000*i);
    				count = 0;
    			}
    		}
    		
    		closeReader();
    		
    		return ret;
    	}
    	
    	public static void makeSampleData(String inputPath,boolean isTitle,String outputPath,int threshold) throws Exception {
    		
    		fr = new FileReader(inputPath);
    		br = new BufferedReader(fr);
    		initWriter1(outputPath);
    		
    		if (isTitle) {
    			line = br.readLine();
    		}
    		int count = 0;
    		while((line = br.readLine()) != null){
    			ps1.println(line);
    			count++;
    			if (count == threshold) {
    				break;
    			}
    		}
    		closeReader();
    	}
    	public static List<String> traverseFolder(String dir) {
            File file = new File(dir);
            String[] fileList = null;
            if (file.exists()) {
            	fileList = file.list();
            }
            List<String> list = new ArrayList<String>();
            for(String path : fileList){
            	list.add(path);
            }
            return list;
        }
    	public static Map<String, List<Score>> loadScoreMap(String path, boolean isTitle, String token, String type) throws Exception {
    		fr = new FileReader(path);
    		br = new BufferedReader(fr);
    		
    		if (isTitle) {
    			line = br.readLine();
    		}
    		
    		Map<String, List<Score>> scoreMap = new HashMap<String, List<Score>>();
    		
    		while((line = br.readLine()) != null){
    			String[] arr = line.split(token);
    			Score score = null;
    			switch (type) {
    			case "userCF":
    				score = ParseTool.parseScoreByItemCF(arr);
    				break;
    			case "itemCF":
    				score = ParseTool.parseScoreByUserCF(arr);
    				break;
    			default:
    				break;
    			}
    			List<Score> temp = new ArrayList<Score>();
    			if (scoreMap.containsKey(score.getItemId())) {
    				temp = scoreMap.get(score.getItemId());
    			}
    			temp.add(score);
    			scoreMap.put(score.getItemId(), temp);
    		}
    		closeReader();
    		return scoreMap;
    	}
    	
    	public static Map<String, List<String>> loadPredictData(String path, boolean isTitle, String token, int n) throws Exception {
    		fr = new FileReader(path);
    		br = new BufferedReader(fr);
    		
    		if (isTitle) {
    			line = br.readLine();
    		}
    		Map<String, List<String>> map = new HashMap<String, List<String>>();
    		while((line = br.readLine()) != null){
    			String[] arr = line.split(token);
    			String userId = arr[0];
    			String itemId = arr[1];
    			List<String> temp = new ArrayList<String>();
    			if (map.containsKey(userId)) {
    				temp = map.get(userId);
    			}
    			if (!temp.contains(itemId) && temp.size() <= n) {
    				temp.add(itemId);
    				map.put(userId, temp);
    				count++;
    			}
    		}
    		
    		closeReader();
    		return map;
    	}
    	
    	public static Map<String, List<String>> loadTestData(Map<String, List<String>> predictMap, String dir, boolean isTitle, String token) throws Exception {
    		
    		List<String> fileList = traverseFolder(dir);
    		Set<String> predictKeySet = predictMap.keySet();
    		Map<String, List<String>> testMap = new HashMap<String, List<String>>();
    		for(String predictKey : predictKeySet){
    			if (fileList.contains(predictKey)) {
    				List<String> itemList = getIdList(dir + predictKey, isTitle, token);
    				testMap.put(predictKey, itemList);
    			}
    		}
    		return testMap;
    	}
    	
    	public static List<String> getIdList(String path, boolean isTitle, String token) throws Exception {
    		fr = new FileReader(path);
    		br = new BufferedReader(fr);
    		
    		if (isTitle) {
    			line = br.readLine();
    		}
    		
    		List<String> list = new ArrayList<String>();
    		while((line = br.readLine()) != null){
    			String[] arr = line.split(token);
    			if (!list.contains(arr[0].trim())) {
    				list.add(arr[0].trim());
    			}
    			count++;
    		}
    		
    		closeReader();
    		return list;
    	}
    	
    	public static Map<String, Double> loadUser_ItemData(String path,boolean isTitle,String token) throws Exception {
    		fr = new FileReader(path);
    		br = new BufferedReader(fr);
    		
    		if (isTitle) {
    			line = br.readLine();
    		}
    		Map<String, Double> map = new HashMap<String, Double>();
    		while((line = br.readLine()) != null){
    			String[] arr = line.split(token);
    			String itemId = arr[1];
    			double score = Double.valueOf(arr[2]);
    			if(map.containsKey(itemId)){
    				double temp = map.get(itemId);
    				if (temp > score) {
    					score = temp;
    				}
    			}
    			map.put(itemId, score);
    		}
    		closeReader();
    		return map;
    	}
    	
    	public static void makeSampleData(String path, boolean isTitle,String token, List<String> userList, List<String> itemList) throws Exception {
    		fr = new FileReader(path);
    		br = new BufferedReader(fr);
    		
    		if (isTitle) {
    			line = br.readLine();
    		}
    		
    		while((line = br.readLine()) != null){
    			String[] arr = line.split(token);
    			String userId = arr[0];
    			String itemId = arr[1];
    			if (userList.contains(userId) && itemList.contains(itemId)) {
    				FileTool.ps1.println(line);
    			}
    		}
    		
    		closeReader();
    		
    	}
    	
    }
    

    解析工具:

    package util;
    
    import entity.Item;
    import entity.Score;
    import entity.User;
    
    public class ParseTool {
    	
    	public static boolean isNumber(String str) {
    		int i,n;
    		n = str.length();
    		for(i = 0;i < n;i++){
    			if (!Character.isDigit(str.charAt(i))) {
    				return false;
    			}
    		}
    		return true;
    	}
    	
    	public static Item parseItem(String[] contents) {
    		Item item = new Item();
    		if (contents[0] != null && !contents[0].isEmpty()) {
    			item.setItemId(contents[0].trim());
    		}
    		if (contents[1] != null && !contents[1].isEmpty()) {
    			item.setItemGeoHash(contents[1].trim());
    		}
    		if (contents[2] != null && !contents[2].isEmpty()) {
    			item.setItemCategory(contents[2].trim());
    		}
    		return item;
    	}
    	public static User parseUser(String[] contents, String type) {
    		User user = new User();
    		int n = contents.length;
    		if (contents[0] != null && !contents[0].isEmpty()) {
    			user.setUserId(contents[0].trim());
    		}
    		if (contents[1] != null && !contents[1].isEmpty()) {
    			user.setItemId(contents[1].trim());
    		}
    		if ("mapUser".equals(type)) {
    			// 1.调用SpliteFileAndMakeScoreTable需放开,其它需注释
    			if (contents[2] != null && !contents[2].isEmpty()) {
    				user.setBehaviorType(Double.valueOf(contents[2].trim()));
    			}
    			/*
    			// sample2
    			if (contents[3] != null && !contents[3].isEmpty()) {
    				user.setUserGeoHash(contents[3].trim());
    			}
    			if (contents[4] != null && !contents[4].isEmpty()) {
    				user.setItemCategory(contents[4].trim());
    			}
    			if (contents[5] != null && !contents[5].isEmpty()) {
    				user.setTime(contents[5].trim());
    			}
    			*/
    			
    			// movielens
    			if (contents[3] != null && !contents[3].isEmpty()) {
    				user.setTime(contents[3].trim());
    			}
    		}
    		if ("reduceUser".equals(type)) {
    			// 2.调用ReducefileTest需放开,其它需注释
    			if (contents[2] != null && !contents[2].isEmpty()) {
    				user.setBehaviorType(Double.parseDouble(contents[2].trim()));
    			}
    			if (contents[n-1] != null && !contents[n-1].isEmpty()) {
    				user.setCount(Integer.valueOf(contents[n-1].trim()));
    			}
    		}
    		if ("predict".equals(type)) {
    			// 3.调用PredictTest需放开,其它需注释
    			if (contents[n-1] != null && !contents[n-1].isEmpty()) {
    				user.setWeight(Double.valueOf(contents[n-1].trim()));
    			}
    		}
    		return user;
    	}
    	public static Score parseScoreByUserCF(String[] contents) {
    		Score score = new Score();
    		if (contents[0] != null && !contents[0].isEmpty()) {
    			score.setUserId(contents[0].trim());
    		}
    		if (contents[1] != null && !contents[1].isEmpty()) {
    			score.setItemId(contents[1].trim());
    		}
    		if (contents[2] != null && !contents[2].isEmpty() && !"Infinity".equals(contents[2])) {
    			double score_temp = Double.parseDouble(contents[2].trim());
    			if (score_temp < 0.0001) {
    				score_temp = 0;
    			}
    			score.setScore(score_temp);
    		}
    		return score;
    	}
    	public static Score parseScoreByItemCF(String[] contents) {
    		Score score = new Score();
    		if (contents[0] != null && !contents[0].isEmpty()) {
    			score.setItemId(contents[0].trim());
    		}
    		if (contents[1] != null && !contents[1].isEmpty()) {
    			score.setUserId(contents[1].trim());
    		}
    		if (contents[2] != null && !contents[2].isEmpty() && !"Infinity".equals(contents[2])) {
    			double score_temp = Double.parseDouble(contents[2].trim());
    			if (score_temp < 0.0001) {
    				score_temp = 0;
    			}
    			score.setScore(score_temp);
    		}
    		return score;
    	}
    }
    

    3.    数据处理模块:

    基于用户的协同过滤数据处理模块:

    package service;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.LinkedHashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.Map.Entry;
    
    import util.FileTool;
    import entity.Item;
    import entity.Score;
    import entity.User;
    
    public class DataProcessByUserCF {
    	
    	public static final double[] w = {0,10,20,30}; 
    	
    	public static void output(Map<String, Map<String, List<User>>> userMap,String outputPath) {
    		for(Entry<String, Map<String, List<User>>> entry : userMap.entrySet()){
    			FileTool.initWriter1(outputPath + entry.getKey());
    			Map<String, List<User>> temp = entry.getValue();
    			for(Entry<String, List<User>> tempEntry : temp.entrySet()){
    				List<User> users = tempEntry.getValue();
    				int count = users.size();
    				for(User user : users){
    					FileTool.ps1.print(user.getUserId() + "\t");
    					FileTool.ps1.print(user.getItemId() + "\t");
    					FileTool.ps1.print(user.getBehaviorType() + "\t");
    					//FileTool.ps1.print(user.getUserGeoHash() + "\t");
    					//FileTool.ps1.print(user.getItemCategory() + "\t");
    					//FileTool.ps1.print(user.getTime() + "\t");
    					FileTool.ps1.print(count + "\n");
    				}
    			}
    		}
    		FileTool.closeWriter1();
    	}
    	
    	public static void output(Map<String, Map<String, Double>> scoreTable, String outputPath, Set<String> userSet, Set<String> itemSet, String token) {
    		FileTool.initWriter1(outputPath);
    		
    		for(String itemId: itemSet){
    			FileTool.ps1.print(token + itemId);
    		}
    		FileTool.ps1.println();
    		for(String userId : userSet){
    			FileTool.ps1.print(userId + token);
    			Map<String, Double> itemMap = scoreTable.get(userId);
    			for(String itemId: itemSet){
    				if(itemMap.containsKey(itemId)){
    					FileTool.ps1.print(itemMap.get(itemId));
    				}else {
    					//FileTool.ps1.print(0);
    				}
    				FileTool.ps1.print(token);
    			}
    			FileTool.ps1.print("\n");
    		}
    	}
    	
    	public static void outputUser(List<User> userList) {
    		for(User user : userList){
    			FileTool.ps1.println(user.getUserId() + "\t" + user.getItemId() + "\t" + user.getWeight());
    		}
    	}
    	
    	public static void outputScore(List<Score> scoreList) {
    		for(Score score : scoreList){
    			FileTool.ps1.println(score.getUserId() + "\t" + score.getItemId() + "\t" + score.getScore());
    		}
    	}
    	
    	public static void outputRecommendList(Map<String, Set<String>> map) {
    		for(Entry<String, Set<String>> entry : map.entrySet()){
    			String userId = entry.getKey();
    			Set<String> itemSet = entry.getValue();
    			for(String itemId : itemSet){
    				FileTool.ps1.println(userId + "," + itemId);
    			}
    		}
    	}
    	
    	public static void output(Map<String, Set<String>> map) {
    		for(Entry<String, Set<String>> entry : map.entrySet()){
    			String userId = entry.getKey();
    			Set<String> set = entry.getValue();
    			for(String itemId : set){
    				FileTool.ps1.println(userId + "\t" + itemId);
    			}
    		}
    	}
    	
    	public static Map<String, Map<String, List<User>>> mapByUser(List<User> userList,Set<String> userSet,Set<String> itemSet) {
    		Map<String, Map<String, List<User>>> userMap = new HashMap<>();
    		for(User user: userList){
    			Map<String, List<User>> tempMap = new HashMap<String, List<User>>();
    			List<User> tempList = new ArrayList<User>();
    			if (!userMap.containsKey(user.getUserId())) {
    			}else {
    				tempMap = userMap.get(user.getUserId());
    				if (!tempMap.containsKey(user.getItemId())) {
    				}else {
    					tempList = tempMap.get(user.getItemId());
    				}
    			}
    			tempList.add(user);
    			tempMap.put(user.getItemId(), tempList);
    			userMap.put(user.getUserId(), tempMap);
    			userSet.add(user.getUserId());
    			itemSet.add(user.getItemId());
    			
    		}
    		return userMap;
    	}
    	
    	public static Map<String, Map<String, Double>> makeScoreTable(Map<String, Map<String, List<User>>> userMap) {
    		Map<String, Map<String, Double>> scoreTable = new HashMap<String, Map<String,Double>>();
    		for(Entry<String, Map<String, List<User>>> userEntry : userMap.entrySet()){
    			
    			Map<String, List<User>> itemMap = userEntry.getValue();
    			String userId = userEntry.getKey();
    			
    			Map<String, Double> itemScoreMap = new HashMap<String, Double>();
    			
    			for(Entry<String, List<User>> itemEntry : itemMap.entrySet()){
    				String itemId = itemEntry.getKey();
    				List<User> users = itemEntry.getValue();
    				double weight = 0.0;
    				
    				double maxType = 0;
    				for(User user : users){
    					if (user.getBehaviorType() > maxType) {
    						maxType = user.getBehaviorType();
    					}
    				}
    				
    				int count = users.size();
    				if (maxType != 0) {
    					//weight += w[(int)maxType-1]; //sample2
    					weight += (maxType-1) * 10; //movielens
    				}
    				weight += count;
    				
    				itemScoreMap.put(itemId, weight);
    			}
    			scoreTable.put(userId, itemScoreMap);
    		}
    		return scoreTable;
    	}
    	public static double calculateWeight(double behaviorType, int count) {
    		//double weight = w[(int)(behaviorType)-1] + count; //sample2
    		double weight = (behaviorType - 1) * 10 + count; //movielens
    		return weight;
    	}
    	public static List<User> reduceUserByItem(List<User> userList) {
    		List<User> list = new ArrayList<User>();
    		Map<String, User> userMap = new LinkedHashMap<String, User>();
    		for(User user : userList){
    			List<String> itemList = new ArrayList<String>();
    			String itemId = user.getItemId();
    			if (!userMap.containsKey(itemId)) {
    				double weight = calculateWeight(user.getBehaviorType(), user.getCount());
    				user.setWeight(weight);
    				userMap.put(itemId, user);
    				list.add(user);
    			}else {
    				User temp = userMap.get(itemId);
    				double weight = calculateWeight(user.getBehaviorType(), user.getCount());
    				if (temp.getWeight() < weight) {
    					user.setWeight(weight);
    					userMap.put(itemId, user);
    					list.remove(temp);
    					list.add(user);
    				}
    			}
    		}
    		userMap.clear();
    		return list;
    	}
    	
    	public static void sortScoreMap(Map<String, List<Score>> scoreMap) {
    		Set<String> userSet = scoreMap.keySet();
    		for(String userId : userSet){
    			List<Score> temp = scoreMap.get(userId);
    			Collections.sort(temp);
    			scoreMap.put(userId, temp);
    		}
    	}
    	public static Map<String, Set<String>> predict(Map<String, List<Score>> scoreMap, List<String> fileNameList, String userDir, int topNUser, double score_threshold, int topNItem, double weight_threshold) throws Exception {
    		Map<String, Set<String>> recommendList = new HashMap<String, Set<String>>();
    		for(Entry<String, List<Score>> entry : scoreMap.entrySet()){
    			String userId1 = entry.getKey();
    			List<Score> list = entry.getValue();
    			int countUser = 0;
    			Set<String> predictItemSet = new LinkedHashSet<String>();
    			for(Score score : list){
    				if (score.getScore() <= score_threshold) {
    					break;
    				}
    				String userId2 = score.getUserId();
    				if(fileNameList.contains(userId2)){
    					List<User> userList = FileTool.readFileOne(userDir + userId2, false, "\t", "user", "predict");
    					int countItem = 0;
    					for(User user : userList){
    						if (user.getWeight() <= weight_threshold) {
    							continue;
    						}
    						predictItemSet.add(user.getItemId());
    						countItem++;
    						if (countItem == topNItem) {
    							break;
    						}
    						
    					}
    					countUser++;
    				}
    				if (countUser == topNUser) {
    					break;
    				}
    			}
    			recommendList.put(userId1, predictItemSet);
    		}
    		return recommendList;
    	}
    	public static void prediction(Map<String, List<String>> predictMap,int predictN, Map<String, List<String>> referenceMap, int refN) {
    		
    		for(int i = 1;i <= 10;i++){
    			int count = 0;
    			predictN = 0;
    			for(Entry<String, List<String>> predictEntity : predictMap.entrySet()){
    				String userId = predictEntity.getKey();
    				if (referenceMap.containsKey(userId)) {
    					List<String> predictList = predictEntity.getValue();
    					int j = 0;
    					for(String itemId : predictList){
    						predictN++;
    						if (referenceMap.get(userId).contains(itemId)) {
    							count++;
    						}
    						j++;
    						if (j == i) {
    							break;
    						}
    					}
    				}
    			}
    			
    			double precision = (1.0 * count / predictN) * 100;
    			double recall = (1.0 * count / refN) * 100;
    			if (recall > 100) {
    				recall = 100;
    			}
    			double f1 = (2 * precision * recall)/(precision + recall);
    			//System.out.println(predictN);
    			//System.out.println(refN);
    			System.out.println("推荐个数:" + i + ",中标个数:" + count + ",推荐总个数:" + predictN + ",真实购买个数:" + refN + ",precision:" + count + "/" + predictN + "=" + precision + "%,recall:" + count + "/" + refN + "=" + recall + "%,f1:" + f1 + "%");
    			
    		}
    		
    		
    	}
    	
    }
    

     基于item的协同过滤数据处理模块:

    package service;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.LinkedHashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.Map.Entry;
    
    import util.FileTool;
    import entity.Item;
    import entity.Score;
    import entity.User;
    
    public class DataProcessByItemCF {
    	
    	public static final double[] w = {0,10,20,30}; 
    	
    	public static void output(Map<String, Map<String, List<User>>> userMap,String outputPath) {
    		for(Entry<String, Map<String, List<User>>> entry : userMap.entrySet()){
    			FileTool.initWriter1(outputPath + entry.getKey());
    			Map<String, List<User>> temp = entry.getValue();
    			for(Entry<String, List<User>> tempEntry : temp.entrySet()){
    				List<User> users = tempEntry.getValue();
    				int count = users.size();
    				for(User user : users){
    					FileTool.ps1.print(user.getUserId() + "\t");
    					FileTool.ps1.print(user.getItemId() + "\t");
    					FileTool.ps1.print(user.getBehaviorType() + "\t");
    					//FileTool.ps1.print(user.getUserGeoHash() + "\t");
    					//FileTool.ps1.print(user.getItemCategory() + "\t");
    					//FileTool.ps1.print(user.getTime() + "\t");
    					FileTool.ps1.print(count + "\n");
    				}
    			}
    			FileTool.closeWriter1();
    		}
    	}
    	
    	public static void output(Map<String, Map<String, Double>> scoreTable, String outputPath, Set<String> userSet, Set<String> itemSet, String token) {
    		FileTool.initWriter1(outputPath);
    		
    		for(String userId: userSet){
    			FileTool.ps1.print(token + userId);
    		}
    		FileTool.ps1.println();
    		for(String itemId : itemSet){
    			FileTool.ps1.print(itemId + token);
    			Map<String, Double> userMap = scoreTable.get(itemId);
    			for(String userId: userSet){
    				if(userMap.containsKey(userId)){
    					FileTool.ps1.print(userMap.get(userId));
    				}else {
    					//FileTool.ps1.print(0);
    				}
    				FileTool.ps1.print(token);
    			}
    			FileTool.ps1.print("\n");
    		}
    		
    		FileTool.closeWriter1();
    	}
    	
    	public static void outputUser(List<User> userList) {
    		for(User user : userList){
    			FileTool.ps1.println(user.getUserId() + "\t" + user.getItemId() + "\t" + user.getWeight());
    		}
    	}
    	
    	public static void outputScore(List<Score> scoreList) {
    		for(Score score : scoreList){
    			FileTool.ps1.println(score.getUserId() + "\t" + score.getItemId() + "\t" + score.getScore());
    		}
    	}
    	
    	public static void outputRecommendList(Map<String, Set<String>> map) {
    		for(Entry<String, Set<String>> entry : map.entrySet()){
    			String userId = entry.getKey();
    			Set<String> itemSet = entry.getValue();
    			for(String itemId : itemSet){
    				FileTool.ps1.println(userId + "," + itemId);
    			}
    		}
    	}
    	
    	public static void output(Map<String, Set<String>> map) {
    		for(Entry<String, Set<String>> entry : map.entrySet()){
    			String userId = entry.getKey();
    			Set<String> set = entry.getValue();
    			for(String itemId : set){
    				FileTool.ps1.println(userId + "\t" + itemId);
    			}
    		}
    	}
    	
    	public static Map<String, Map<String, List<User>>> mapByUser(List<User> userList, Set<String> userSet, Set<String> itemSet) {
    		Map<String, Map<String, List<User>>> userMap = new HashMap<>();
    		for(User user: userList){
    			Map<String, List<User>> tempMap = new HashMap<String, List<User>>();
    			List<User> tempList = new ArrayList<User>();
    			if (!userMap.containsKey(user.getUserId())) {
    			}else {
    				tempMap = userMap.get(user.getUserId());
    				if (!tempMap.containsKey(user.getItemId())) {
    				}else {
    					tempList = tempMap.get(user.getItemId());
    				}
    			}
    			tempList.add(user);
    			tempMap.put(user.getItemId(), tempList);
    			userMap.put(user.getUserId(), tempMap);
    			//userMap.put(user.getItemId(), tempMap);
    			userSet.add(user.getUserId());
    			itemSet.add(user.getItemId());
    			
    		}
    		return userMap;
    	}
    	
    	public static Map<String, Map<String, Double>> makeScoreTable(Map<String, Map<String, List<User>>> userMap) {
    		Map<String, Map<String, Double>> scoreTable = new LinkedHashMap<>();
    		for(Entry<String, Map<String, List<User>>> userEntry : userMap.entrySet()){
    			
    			Map<String, List<User>> itemMap = userEntry.getValue();
    			String userId = userEntry.getKey();
    			
    			Map<String, Double> userScoreMap;
    			
    			for(Entry<String, List<User>> itemEntry : itemMap.entrySet()){
    				String itemId = itemEntry.getKey();
    				List<User> users = itemEntry.getValue();
    				double weight = 0.0;
    				
    				double maxType = 0;
    				for(User user : users){
    					if (user.getBehaviorType() > maxType) {
    						maxType = user.getBehaviorType();
    					}
    				}
    				
    				int count = users.size();
    				if (maxType != 0) {
    					//weight += w[(int)maxType-1]; //sample2
    					weight += (maxType-1) * 10; //movielens
    				}
    				weight += count;
    				
    				if (scoreTable.containsKey(itemId)) {
    					userScoreMap = scoreTable.get(itemId);
    				}else {
    					userScoreMap = new LinkedHashMap<String, Double>();
    				}
    				
    				userScoreMap.put(userId, weight);
    				
    				scoreTable.put(itemId, userScoreMap);
    				
    			}
    			
    		}
    		return scoreTable;
    	}
    	public static double calculateWeight(double behaviorType, int count) {
    		//double weight = w[(int)(behaviorType)-1] + count; //sample2
    		double weight = (behaviorType - 1) * 10 + count; //movielens
    		return weight;
    	}
    	public static List<User> reduceUserByItem(List<User> userList) {
    		List<User> list = new ArrayList<User>();
    		Map<String, User> userMap = new LinkedHashMap<String, User>();
    		for(User user : userList){
    			List<String> itemList = new ArrayList<String>();
    			String itemId = user.getItemId();
    			if (!userMap.containsKey(itemId)) {
    				double weight = calculateWeight(user.getBehaviorType(), user.getCount());
    				user.setWeight(weight);
    				userMap.put(itemId, user);
    				list.add(user);
    			}else {
    				User temp = userMap.get(itemId);
    				double weight = calculateWeight(user.getBehaviorType(), user.getCount());
    				if (temp.getWeight() < weight) {
    					user.setWeight(weight);
    					userMap.put(itemId, user);
    					list.remove(temp);
    					list.add(user);
    				}
    			}
    		}
    		userMap.clear();
    		return list;
    	}
    	
    	public static void sortScoreMap(Map<String, List<Score>> scoreMap) {
    		Set<String> userSet = scoreMap.keySet();
    		for(String userId : userSet){
    			List<Score> temp = scoreMap.get(userId);
    			Collections.sort(temp);
    			scoreMap.put(userId, temp);
    		}
    	}
    	public static Map<String, Set<String>> predict(Map<String, List<Score>> scoreMap, List<String> fileNameList, String userDir, int topNUser, double score_threshold, int topNItem, double weight_threshold) throws Exception {
    		Map<String, Set<String>> recommendList = new HashMap<String, Set<String>>();
    		
    		for(String userFileName : fileNameList){
    			//System.out.println("userFileName:"+userFileName);
    			List<User> userList = FileTool.readFileOne(userDir + userFileName, false, "\t", "user", "predict");
    			//System.out.println("userList:"+userList);
    			for(User user : userList){
    				String userId = user.getUserId();
    				if (user.getWeight() <= weight_threshold) {
    					continue;
    				}
    				String itemId = user.getItemId();
    				List<Score> itemSimilarList = scoreMap.get(itemId);
    				//System.out.println("itemSimilarList:"+itemSimilarList);
    				Set<String> predictItemSet;
    				
    				if (recommendList.containsKey(userId)) {
    					predictItemSet = recommendList.get(userId);
    				}else {
    					predictItemSet = new LinkedHashSet<String>();
    				}
    				
    				int countItem = 0;
    				for(Score similarItem : itemSimilarList){
    					predictItemSet.add(similarItem.getUserId());
    					if (countItem == topNItem) {
    						break;
    					}
    					countItem++;
    				}
    				recommendList.put(userId, predictItemSet);
    			}
    		}
    
    		return recommendList;
    	}
    	public static void prediction(Map<String, List<String>> predictMap,int predictN, Map<String, List<String>> referenceMap, int refN) {
    		int count = 0;
    		for(Entry<String, List<String>> predictEntity : predictMap.entrySet()){
    			String userId = predictEntity.getKey();
    			if (referenceMap.containsKey(userId)) {
    				List<String> predictList = predictEntity.getValue();
    				for(String itemId : predictList){
    					if (referenceMap.get(userId).contains(itemId)) {
    						count++;
    					}
    				}
    			}
    		}
    		double precision = (1.0 * count / predictN) * 100;
    		double recall = (1.0 * count / refN) * 100;
    		double f1 = (2 * precision * recall)/(precision + recall);
    		System.out.println("precision="+precision+",recall="+recall+",f1="+f1);
    	}
    	
    }
    

    4.    计算模块

    基于用户的协同过滤计算相似度模块

    package service;
    
    import java.text.DecimalFormat;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    
    import util.FileTool;
    
    public class CalculateSimilarityByUserCF {
    	
    	public static DecimalFormat df = new DecimalFormat("#.0000");
    	
    	//计算方式有问题,如(a):1,0,1与1,20,1计算相似度和(b):0,1,0与0,0,0,(b)反而比(a)近
    	public static double EuclidDist(Map<String, Double> userMap1,
    			Map<String, Double> userMap2, Set<String> userSet,
    			Set<String> itemSet) {
    		double sum = 0;
    		for (String itemId : itemSet) {
    			double score1 = 0.0;
    			double score2 = 0.0;
    			if (userMap1.containsKey(itemId) && userMap2.containsKey(itemId)) {
    				score1 = userMap1.get(itemId);
    				score2 = userMap2.get(itemId);
    			} else if (userMap1.containsKey(itemId)) {
    				score1 = userMap1.get(itemId);
    			} else if (userMap2.containsKey(itemId)) {
    				score2 = userMap2.get(itemId);
    			}
    			double temp = Math.pow((score1 - score2), 2);
    			sum += temp;
    		}
    		sum = Math.sqrt(sum);
    		return sum;
    	}
    
    	public static double CosineDist(Map<String, Double> userMap1,
    			Map<String, Double> userMap2, Set<String> userSet,
    			Set<String> itemSet) {
    		double dist = 0;
    		double numerator = 1; // 分子
    		double denominator1 = 0; // 分母
    		double denominator2 = 0; // 分母
    		for (String itemId : itemSet) {
    			double score1 = 0.0;
    			double score2 = 0.0;
    			if (userMap1.containsKey(itemId) && userMap2.containsKey(itemId)) {
    				//numerator++;
    				score1 = userMap1.get(itemId);
    				score2 = userMap2.get(itemId);
    				numerator = numerator * (score1 * score2);
    			} else if (userMap1.containsKey(itemId)) {
    				score1 = userMap1.get(itemId);
    			} else if (userMap2.containsKey(itemId)) {
    				score2 = userMap2.get(itemId);
    			}
    			denominator1 += Math.pow(score1, 2);
    			denominator2 += Math.pow(score2, 2);
    		}
    		dist = ((1.0 * numerator) / (Math.sqrt(denominator1) * Math.sqrt(denominator2)));
    		return dist;
    	}
    	
    	public static double execute(Map<String, Double> userMap1,Map<String, Double> userMap2,Set<String> userSet,Set<String> itemSet) {
    		/*
    		double dist = EuclidDist(userMap1, userMap2, userSet, itemSet);
    		double userScore = 1.0 / (1.0 + dist);
    		*/
    		double userScore = CosineDist(userMap1, userMap2, userSet, itemSet);
    		return userScore;
    	}
    
    	public static void execute(String userId,Map<String, Map<String, Double>> scoreTable,
    			Set<String> userSet, Set<String> itemSet) {
    		for (Entry<String, Map<String, Double>> userEntry : scoreTable.entrySet()) {
    			String userId2 = userEntry.getKey();
    			Map<String, Double> userMap2 = userEntry.getValue();
    			//double dist = EuclidDist(scoreTable.get(userId), userMap2, userSet, itemSet);
    			//double userScore = 1.0 / (1.0 + dist);
    			double userScore = CosineDist(scoreTable.get(userId), userMap2, userSet, itemSet);
    			FileTool.ps1.println(userId + "," + userId2 + "," + df.format(userScore));
    		}
    	}
    
    	public static void execute(Map<String, Map<String, Double>> scoreTable,
    			Set<String> userSet, Set<String> itemSet) {
    		int count = 0;
    		for (Entry<String, Map<String, Double>> userEntry1 : scoreTable.entrySet()) {
    			long startTime = System.currentTimeMillis();
    			String userId = userEntry1.getKey();
    			execute(userId, scoreTable, userSet, itemSet);
    			count++;
    			long endTime = System.currentTimeMillis();
    			long dur = endTime - startTime;
    			System.out.println("user count:" + count + ",dur time:" + dur + "," + (dur/1000) + "s," + (dur/1000/60) + "m");
    		}
    	}
    
    }
    
    

     基于item的协同过滤计算相似度模块

    package service;
    
    import java.text.DecimalFormat;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    
    import util.FileTool;
    
    public class CalculateSimilarityByItemCF {
    	
    	public static DecimalFormat df = new DecimalFormat("#.0000");
    	
    	//计算方式有问题,如(a):1,0,1与1,20,1计算相似度和(b):0,1,0与0,0,0,(b)反而比(a)近
    	public static double EuclidDist(Map<String, Double> userMap1,
    			Map<String, Double> userMap2, Set<String> userSet,
    			Set<String> itemSet) {
    		double sum = 0;
    		for (String userId : userSet) {
    			double score1 = 0.0;
    			double score2 = 0.0;
    			if (userMap1.containsKey(userId) && userMap2.containsKey(userId)) {
    				score1 = userMap1.get(userId);
    				score2 = userMap2.get(userId);
    			} else if (userMap1.containsKey(userId)) {
    				score1 = userMap1.get(userId);
    			} else if (userMap2.containsKey(userId)) {
    				score2 = userMap2.get(userId);
    			}
    			double temp = Math.pow((score1 - score2), 2);
    			sum += temp;
    		}
    		sum = Math.sqrt(sum);
    		return sum;
    	}
    
    	public static double CosineDist(Map<String, Double> userMap1,
    			Map<String, Double> userMap2, Set<String> userSet,
    			Set<String> itemSet) {
    		double dist = 0;
    		double numerator = 1; // 分子
    		double denominator1 = 0; // 分母
    		double denominator2 = 0; // 分母
    		for (String userId : userSet) {
    			double score1 = 0.0;
    			double score2 = 0.0;
    			if (userMap1.containsKey(userId) && userMap2.containsKey(userId)) {
    				//numerator++;
    				score1 = userMap1.get(userId);
    				score2 = userMap2.get(userId);
    				numerator = numerator * (score1 * score2);
    			} else if (userMap1.containsKey(userId)) {
    				score1 = userMap1.get(userId);
    			} else if (userMap2.containsKey(userId)) {
    				score2 = userMap2.get(userId);
    			}
    			denominator1 += Math.pow(score1, 2);
    			denominator2 += Math.pow(score2, 2);
    		}
    		dist = ((1.0 * numerator) / (Math.sqrt(denominator1) * Math.sqrt(denominator2)));
    		return dist;
    	}
    	
    	public static double SimpleDist(Map<String, Double> userMap1,
    			Map<String, Double> userMap2, Set<String> userSet,
    			Set<String> itemSet) {
    		double dist = 0;
    		double numerator = 0; // 分子
    		double denominator1 = 0; // 分母
    		double denominator2 = 0; // 分母
    		for (String userId : userSet) {
    			if (userMap1.containsKey(userId) && userMap2.containsKey(userId)) {
    				numerator++;
    				denominator1++;
    				denominator2++;
    			} else if (userMap1.containsKey(userId)) {
    				denominator1++;
    			} else if (userMap2.containsKey(userId)) {
    				denominator2++;
    			}
    		}
    		dist = ((1.0 * numerator) / (Math.sqrt(denominator1) * Math.sqrt(denominator2)));
    		return dist;
    	}
    	
    	public static double execute(Map<String, Double> userMap1,Map<String, Double> userMap2,Set<String> userSet,Set<String> itemSet) {
    		/*
    		double dist = EuclidDist(userMap1, userMap2, userSet, itemSet);
    		double userScore = 1.0 / (1.0 + dist);
    		*/
    		double userScore = CosineDist(userMap1, userMap2, userSet, itemSet);
    		return userScore;
    	}
    
    	public static void execute(String itemId, Map<String, Map<String, Double>> scoreTable,
    			Set<String> userSet, Set<String> itemSet) {
    		for (Entry<String, Map<String, Double>> itemEntry : scoreTable.entrySet()) {
    			String itemId2 = itemEntry.getKey();
    			Map<String, Double> userMap2 = itemEntry.getValue();
    			//double dist = EuclidDist(scoreTable.get(itemId), userMap2, userSet, itemSet);
    			//double userScore = 1.0 / (1.0 + dist);
    			//double userScore = CosineDist(scoreTable.get(itemId), userMap2, userSet, itemSet);
    			double userScore = SimpleDist(scoreTable.get(itemId), userMap2, userSet, itemSet);
    			FileTool.ps1.println(itemId + "," + itemId2 + "," + df.format(userScore));
    		}
    	}
    
    	public static void execute(Map<String, Map<String, Double>> scoreTable,
    			Set<String> userSet, Set<String> itemSet) {
    		int count = 0;
    		
    		for (Entry<String, Map<String, Double>> itemEntry : scoreTable.entrySet()) {
    			long startTime = System.currentTimeMillis();
    			String itemId = itemEntry.getKey();
    			execute(itemId, scoreTable, userSet, itemSet);
    			count++;
    			long endTime = System.currentTimeMillis();
    			long dur = endTime - startTime;
    			System.out.println("item count:" + count + ",dur time:" + dur + "," + (dur/1000) + "s," + (dur/1000/60) + "m");
    		}
    		
    	}
    
    }
    

    5.    脚本

    生成userset和itemset:

    package script;
    
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    import entity.User;
    import util.FileTool;
    
    public class MakeSet {
    
    	public static void main(String[] args) throws Exception {
    		String inputDir = args[0];
    		String outputDir = args[1];
    		Set<String> userSet = new HashSet<String>();
    		Set<String> itemSet = new HashSet<String>();
    		List<String> pathList = FileTool.traverseFolder(inputDir);
    		for(String path : pathList){
    			String inputPath = inputDir + path;
    			List<User> list = FileTool.readFileOne(inputPath, false, "\t", "user", "reduceUser");
    			for(User user : list){
    				userSet.add(user.getUserId());
    				itemSet.add(user.getItemId());
    			}
    		}
    		FileTool.initWriter1(outputDir+"userSet");
    		for(String userId : userSet){
    			FileTool.ps1.println(userId);
    		}
    		FileTool.closeWriter1();
    		FileTool.initWriter1(outputDir+"itemSet");
    		for(String itemId : itemSet){
    			FileTool.ps1.println(itemId);
    		}
    		FileTool.closeWriter1();
    		
    	}
    
    }
    

    基于用户的协同过滤:map文件构建user-item评分矩阵并计算user间的相似度生成user-user的得分表:

    package script.runByUserCF;
    
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import service.CalculateSimilarityByUserCF;
    import service.DataProcessByUserCF;
    import util.FileTool;
    import entity.User;
    
    public class SpliteFileAndMakeScoreTable {
    	
    	public static void main(String[] args) throws Exception {
    		
    		String inputDir = "data/fresh_comp_offline/sample2/";
    		String outputDir = "data/fresh_comp_offline/sample2/out/user/";
    		String userPath = inputDir + "train_user.csv";
    		String outputPath = "data/fresh_comp_offline/sample2/out/score.csv";
    		String scoreTablePath = "data/fresh_comp_offline/sample2/out/scoreTable.csv";
    		
    		/*
    		String inputDir = "data/ml-1m/";
    		String outputDir = "data/ml-1m/out/user/";
    		String userPath = inputDir + "ratings.dat";
    		String outputPath = "data/ml-1m/out/score.csv";
    		*/
    		/*
    		String inputDir = args[0];
    		String outputDir = args[1];
    		String userPath = inputDir + args[2];
    		String outputPath = args[3];
    		String scoreTablePath = args[4];
    		*/
    		
    		//FileTool.makeSampleData(userPath, true, outputPath, 10000);
    		//List<Object> itemList = FileTool.readFileOne(itemPath, true, ",", "item");
    		List<User> userList = FileTool.readFileOne(userPath, true, ",", "user", "mapUser"); //sample2
    		//List<User> userList = FileTool.readFileOne(userPath, true, "::", "user", "mapUser"); //movielens
    		Set<String> userSet = new HashSet<String>();
    		Set<String> itemSet = new HashSet<String>();
    		Map<String, Map<String, List<User>>> userMap = DataProcessByUserCF.mapByUser(userList,userSet,itemSet);
    		userList.clear();
    		DataProcessByUserCF.output(userMap, outputDir);
    		
    		//生成userToItem的打分表
    		Map<String, Map<String, Double>> scoreTable = DataProcessByUserCF.makeScoreTable(userMap);
    		DataProcessByUserCF.output(scoreTable, scoreTablePath , userSet, itemSet, ",");
    		userMap.clear();
    		FileTool.initWriter1(outputPath);
    		CalculateSimilarityByUserCF.execute(scoreTable, userSet, itemSet);
    		FileTool.closeWriter1();
    		
    	}
    
    }
    

    基于用户的协同过滤,reduce文件,对users排序:

    package script.runByUserCF;
    
    import java.util.Collections;
    import java.util.List;
    
    import service.DataProcessByUserCF;
    import util.FileTool;
    import entity.User;
    
    public class ReduceFileTest {
    	public static void main(String[] args) throws Exception {
    		
    		String inputDir = "data/fresh_comp_offline/sample2/out/user/";
    		String outputDir = "data/fresh_comp_offline/sample2/out/sorteduser/";
    		
    		/*
    		String inputDir = "data/ml-1m/out/user/";
    		String outputDir = "data/ml-1m/out/sorteduser/";
    		*/
    		/*
    		String inputDir = args[0];
    		String outputDir = args[1];
    		*/
    		
    		List<String> pathList = FileTool.traverseFolder(inputDir);
    		for(String path : pathList){
    			List<User> userList = FileTool.readFileOne(inputDir+path, false, "\t", "user", "reduceUser");
    			List<User> list = DataProcessByUserCF.reduceUserByItem(userList);
    			userList.clear();
    			FileTool.initWriter1(outputDir + path);
    			Collections.sort(list);
    			DataProcessByUserCF.outputUser(list);
    			FileTool.closeWriter1();
    			list.clear();
    		}
    	}
    }
    

    基于用户的协同过滤,为用户进行推荐,生成预测列表:

    package script.runByUserCF;
    
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import service.DataProcessByUserCF;
    import util.FileTool;
    import entity.Score;
    
    
    public class PredictTest {
    	public static void main(String[] args) throws Exception {
    		/*
    		String inputDir = "data/fresh_comp_offline/sample2/out/";
    		String outputDir = "data/fresh_comp_offline/sample2/out/";
    		String inputPath = inputDir + "score.csv";
    		String outputPath = outputDir + "predict";
    		String userDir = "data/fresh_comp_offline/sample2/out/sorteduser/";
    		*/
    		
    		String inputDir = "data/fresh_comp_offline/sample2/out/";
    		String outputDir = "data/fresh_comp_offline/sample2/out/";
    		String inputPath = inputDir + "score.csv";
    		String outputPath = outputDir + "predict";
    		String userDir = "data/fresh_comp_offline/sample2/out/sorteduser/";
    		int topNUser = 5;
    		double score_threshold = 0;
    		int topNItem = 5;
    		double weight_threshold = 1.0;
    		
    		/*
    		String inputDir = args[0];
    		String outputDir = args[1];
    		String inputPath = inputDir + args[2];
    		String outputPath = outputDir + args[3];
    		String userDir = args[4];
    		int topNUser = Integer.parseInt(args[5]);
    		double score_threshold = Double.parseDouble(args[6]);
    		int topNItem = Integer.parseInt(args[7]);
    		double weight_threshold = Double.parseDouble(args[8]);
    		*/
    		Map<String, List<Score>> scoreMap = FileTool.loadScoreMap(inputPath, false, ",", "userCF");
    		DataProcessByUserCF.sortScoreMap(scoreMap);
    		List<String> fileNameList = FileTool.traverseFolder(userDir);
    		//我选择推荐该user的最相似的5个user的前5个item
    		Map<String, Set<String>> predictMap = DataProcessByUserCF.predict(scoreMap, fileNameList, userDir, topNUser, score_threshold, topNItem, weight_threshold);
    		FileTool.initWriter1(outputPath);
    		DataProcessByUserCF.outputRecommendList(predictMap);
    		FileTool.closeWriter1();
    		scoreMap.clear();
    	}
    }
    

    基于item的协同过滤:map文件构建user-item评分矩阵并计算item间的相似度生成item-item的得分表:

    package script.runByItemCF;
    
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import service.CalculateSimilarityByItemCF;
    import service.DataProcessByItemCF;
    import util.FileTool;
    import entity.User;
    
    public class SpliteFileAndMakeScoreTable {
    	
    	public static void main(String[] args) throws Exception {
    		/*
    		String inputDir = "D:/workspace/java/recommendSystemDemo/data/unicom/allRecommend/";
    		String outputDir = "D:/workspace/java/recommendSystemDemo/data/unicom/allRecommend/out/user/";
    		String userPath = inputDir + "train_als_itemCF1.csv";
    		String outputPath = "D:/workspace/java/recommendSystemDemo/data/unicom/allRecommend/out/score.csv";
    		String scoreTablePath = "D:/workspace/java/recommendSystemDemo/data/unicom/allRecommend/out/scoreTable.csv";
    		String token = ",";
    		*/
    		
    		
    		String inputDir = args[0];
    		String outputDir = args[1];
    		String userPath = inputDir + args[2];
    		String outputPath = args[3];
    		String scoreTablePath = args[4];
    		String token = args[5];
    		
    		
    		//FileTool.makeSampleData(userPath, true, outputPath, 10000);
    		//List<Object> itemList = FileTool.readFileOne(itemPath, true, ",", "item");
    		//List<User> userList = FileTool.readFileOne(userPath, true, ",", "user", "mapUser"); //sample2
    		//List<User> userList = FileTool.readFileOne(userPath, true, "::", "user", "mapUser"); //movielens
    		List<User> userList = FileTool.readFileOne(userPath, true, token, "user", "mapUser");
    		Set<String> userSet = new HashSet<String>();
    		Set<String> itemSet = new HashSet<String>();
    		Map<String, Map<String, List<User>>> userMap = DataProcessByItemCF.mapByUser(userList,userSet,itemSet);
    		userList.clear();
    		DataProcessByItemCF.output(userMap, outputDir);
    		
    		//生成itemToUser的打分表
    		Map<String, Map<String, Double>> scoreTable = DataProcessByItemCF.makeScoreTable(userMap);
    		DataProcessByItemCF.output(scoreTable, scoreTablePath , userSet, itemSet, ",");
    		userMap.clear();
    		FileTool.initWriter1(outputPath);
    		CalculateSimilarityByItemCF.execute(scoreTable, userSet, itemSet);
    		FileTool.closeWriter1();
    		
    	}
    
    }
    

    基于item的协同过滤,reduce文件,对users排序:

    package script.runByItemCF;
    
    import java.util.Collections;
    import java.util.List;
    
    import service.DataProcessByUserCF;
    import util.FileTool;
    import entity.User;
    
    public class ReduceFileTest {
    	public static void main(String[] args) throws Exception {
    		/*
    		String inputDir = "data/fresh_comp_offline/sample2/out/user/";
    		String outputDir = "data/fresh_comp_offline/sample2/out/sorteduser/";
    		*/
    		/*
    		String inputDir = "data/ml-1m/out/user/";
    		String outputDir = "data/ml-1m/out/sorteduser/";
    		*/
    		
    		String inputDir = args[0];
    		String outputDir = args[1];
    		
    		
    		List<String> pathList = FileTool.traverseFolder(inputDir);
    		for(String path : pathList){
    			List<User> userList = FileTool.readFileOne(inputDir+path, false, "\t", "user", "reduceUser");
    			List<User> list = DataProcessByUserCF.reduceUserByItem(userList);
    			userList.clear();
    			FileTool.initWriter1(outputDir + path);
    			Collections.sort(list);
    			DataProcessByUserCF.outputUser(list);
    			FileTool.closeWriter1();
    			list.clear();
    		}
    	}
    }
    

    基于item的协同过滤,为用户进行推荐,生成预测列表:

    package script.runByItemCF;
    
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import service.DataProcessByItemCF;
    import util.FileTool;
    import entity.Score;
    
    
    public class PredictTest {
    	public static void main(String[] args) throws Exception {
    		/*
    		String inputDir = "data/fresh_comp_offline/sample2/out/";
    		String outputDir = "data/fresh_comp_offline/sample2/out/";
    		String inputPath = inputDir + "score.csv";
    		String outputPath = outputDir + "predict";
    		String userDir = "data/fresh_comp_offline/sample2/out/sorteduser/";
    		int topNUser = 5;
    		double score_threshold = 0;
    		int topNItem = 5;
    		double weight_threshold = 0;
    		*/
    		/*
    		String inputDir = "data/ml-1m/out/out_itemCF/";
    		String outputDir = "data/ml-1m/out/out_itemCF/";
    		String inputPath = inputDir + "score.csv";
    		String outputPath = outputDir + "predict";
    		String userDir = "data/ml-1m/out/out_itemCF/sorteduser/";
    		int topNUser = 5;
    		double score_threshold = 0;
    		int topNItem = 5;
    		double weight_threshold = 0;
    		*/
    		
    		
    		String inputDir = args[0];
    		String outputDir = args[1];
    		String inputPath = inputDir + args[2];
    		String outputPath = outputDir + args[3];
    		String userDir = args[4];
    		int topNUser = Integer.parseInt(args[5]);
    		double score_threshold = Double.parseDouble(args[6]);
    		int topNItem = Integer.parseInt(args[7]);
    		double weight_threshold = Double.parseDouble(args[8]);
    		
    		
    		Map<String, List<Score>> scoreMap = FileTool.loadScoreMap(inputPath, false, ",", "itemCF");
    		DataProcessByItemCF.sortScoreMap(scoreMap);
    		List<String> fileNameList = FileTool.traverseFolder(userDir);
    		//我选择推荐该user的最相似的5个user的前5个item
    		Map<String, Set<String>> predictMap = DataProcessByItemCF.predict(scoreMap, fileNameList, userDir, topNUser, score_threshold, topNItem, weight_threshold);
    		FileTool.initWriter1(outputPath);
    		DataProcessByItemCF.outputRecommendList(predictMap);
    		FileTool.closeWriter1();
    		scoreMap.clear();
    	}
    }
    

    计算准确率、召回率、F测度值:

    package script;
    
    import java.util.List;
    import java.util.Map;
    
    import service.DataProcessByUserCF;
    import util.FileTool;
    
    public class MatchTest {
    
    	public static void main(String[] args) throws Exception {
    		
    		//String predictPath = "data/ml-1m/out/predict_itemCF2";
    		//String predictPath = "data/ml-1m/out/predict_userCF";
    		//String predictPath = "data/ml-1m/out/predict_ALS_15_600_0.388_0.01";
    		//String predictPath = "data/ml-1m/out/predict_ml_ALS_15_600_0.388_0.01_1.csv";
    		//String predictPath = "data/unicom/outRecommend/out/out_outRecommedList3.csv";
    		//String predictPath = "data/unicom/allRecommend/out/out_outRecommedList250_0.4.csv";
    		//String predictPath = "data/unicom/allRecommend/out/predict_als_randomForest.csv";
    		String predictPath = "data/unicom/out/test_pred.txt";
    		
    		//String predictPath = "data/ml-1m/out/predict_ml_userCF_RF.csv";
    		//String predictPath = "data/ml-1m/out/predict_ml_userCF.csv";
    		//String predictPath = "data/ml-1m/out/predict_ml_ALS.csv";
    		//String predictPath = "data/ml-1m/out/predict_ml_all1.csv";
    		//String predictPath = "data/ml-1m/out/predict_ml_ALS_15_600_0.388_0.01.csv";
    		
    		//String referencePath = "data/ml-1m/sample/testData.dat";
    		//String referencePath = "data/unicom/outRecommend/test3_list.csv";
    		//String referencePath = "data/unicom/allRecommend/test_als.csv";
    		String referencePath = "data/unicom/out/test_real.txt";
    		
    		Map<String, List<String>> predictMap = FileTool.loadPredictData(predictPath, false, ",", 50);
    		int predictN = FileTool.count;
    		FileTool.count = 0;
    		Map<String, List<String>> referenceMap = FileTool.loadPredictData(referencePath, false, ",", 10000);
    		int referenceN = FileTool.count;
    		DataProcessByUserCF.prediction(predictMap, predictN, referenceMap, referenceN);
    	}
    
    }
    

    脚本运行顺序:

    (1).基于用户的协同过滤推荐:
    1.script.runByUserCF.SpliteFileAndMakeScoreTable.java //map文件并生成user-user的score
    2.script.runByUserCF.ReduceFileTest.java  //对map后的文件排序,主要对user内的item的score排序
    3.script.runByUserCF.PredictTest.java   //预测,生成预测列表user-item
    4.runMakeTestSet.sh  //生成测试集
    5.runSpliteFile.sh   //对测试集文件进行map
    6.runMatch.sh     //将预测列表与测试集进行匹配,计算预测准确率及召回率
    (2).基于item的协同过滤推荐:
    1.script.runByItemCF.SpliteFileAndMakeScoreTable.java //map文件并生成item-item的score
    2.script.runByItemCF.ReduceFileTest.java  //对map后的文件排序,主要对user内的item的score排序
    3.script.runByItemCF.PredictTest.java   //预测,生成预测列表user-item
    4.runMakeTestSet.sh  //生成测试集
    5.runSpliteFile.sh   //对测试集文件进行map
    6.runMatch.sh     //将预测列表与测试集进行匹配,计算预测准确率及召回率

    以上为核心代码,大家可以参考项目源代码地址:

    https://download.csdn.net/download/u013473512/10141066

    https://github.com/Emmitte/recommendSystem

    欢迎关注“程序杂货铺”公众号,里面有精彩内容,欢迎大家收看^_^

    展开全文
  • 随着企业内部信息化管理的重要程度越来越高,我国OA协同办公产品近年来得以快速发展。其中开源办公产品因为其开源免费的特性受到众多中小企业的喜爱。下面就来说一说那些开源协同产品中的优秀代表们。 NO.1:然之...

    随着企业内部信息化管理的重要程度越来越高,我国OA协同办公产品近年来得以快速发展。其中开源办公产品因为其开源免费的特性受到众多中小企业的喜爱。下面就来说一说那些开源OA协同产品,其中选了几款代表性项目(排名不分先后)

    NO.1:然之协同(PHP)

    开发语言:然之协同以ZPL协议开源发行,采用PHP+MYSQL语言开发。

    功能模块:然之协同由客户管理(CRM)、日常办公、财务记账、文档管理、项目管理、团队分享、应用管理等模块组成,各模块下又分为多个功能点,基本囊括了的各种场景。然之系统还集成了自主研发的聊天工具喧喧及多种第三方WEB应用,应用统一管理,操作简便。

    推荐理由:功能强大,逻辑清晰。和市面上其他的协同产品相比,然之协同更专注于提供一体化、精简的解决方案。

     

    NO.2:O2OA办公平台(JAVA)

    开发语言:O2OA办公平台遵循GPL协议开源发行,采用JAVA语言开发,适配了安卓和IOS移动APP,能深度集成钉钉和企业微微信。

    功能模块:O2OA办 公平台由流程平台、门户平台、信息平台、数据平台和服务平台五大功能组成,开箱即用的功能有考勤管理、信息管理、会议管理、日程管理、便签管理、文件管理、工作管理、脑图工具等功能。通过五大平台,可以轻松地完成企业应用的创建和开发,如公文管理、日常办公、财务记账、项目管理、行政管理、用车管理、报销审批等功能,基本满足了的各种企业场景。

    推荐理由:虽然平台本身并不是大多数应用都已经存在,但强大平台功能,让技术人员能轻松应对企业应用的开发和建设。O2OA完全分布式架构,支持组件级负载均衡和255节点的切片数据库,如此高性能,稳定的开发平台,能真正做到免费使用,无限制使用,着实不容易。

    当然技术支持服务和商用授权是收费的,用户可以根据需求来选购付费方式,如果公司有技术能力,又不商用,刚好又不愿意付费,那么O2OA可能是最好的选择了。

     

    NO.3:PHPOA(PHP)

    开发语言:PHPOA采用PHP+MYSQL语言开发,使用敏捷MVC开发框架。

    功能模块:PHPOA的功能包含个人办公、工作流、公文、人力资源、行政办公、档案、项目管理、知识库、在线交流、CRM系统等多个功能点。适合于企业领域内的多种规范和要求,构成高性能、高可用的信息化管理平台

    推荐理由:PHPOA致力于企事业单位日常管理、审批和业务管理的全面数据化,针对多种企业类型的不同需求,现已推出企业、政府、集团、SAAS等应用平台。

     

     

    NO.4:小微OA系统(PHP)

    开发语言:小微OA系统遵循Apache2开源协议,基于Bootstrap框架开发。

    功能模块:小微OA包含邮件管理、审批流程、信息发布、文档管理、任务协作、工作日报、客户管理等诸多功能。

    推荐理由:小微OA系统针对小微企业的流程管理而设计开发,可以轻松应对随时变动的审核流程。着重打造高效协作、移动办公为主的小微OA管理系统。

     

    NO.5:魔方OA(ASP.NET)

    开发语言:魔方OA是基于微软Asp.net 4.0,SQL Server 2008为基础,兼容高级版本的开源办公系统。

    功能模块:魔方OA包括权限管理、用户管理、部门管理、考勤管理、流程管理、任务管理、邮件、日历、讨论区、通讯论等功能点,还有多种颜色皮肤可以切换。

    推荐理由:魔方OA定位为办公管理系统,针对企业的日常办公管理。它的响应式UI设计,可适应PC、笔记本电脑、iPad/安卓平板/Windows平板,以及各种手机。

    大家可以根据自己的需求来选择,当然现在还有很多的好项目,大家也要多多发现多多体验哦!

    展开全文
  • 协同过滤

    千次阅读 多人点赞 2021-01-24 13:48:09
    协同过滤 什么是协同过滤 协同过滤推荐(Collaborative Filtering recommendation)是在信息过滤和信息系 统中正迅速成为一项很受欢迎的技术。与传统的基于内容过滤直接分析内容进行 推荐不同,协同过滤分析用户兴趣...

    协同过滤

    什么是协同过滤

    协同过滤推荐(Collaborative Filtering recommendation)是在信息过滤和信息系 统中正迅速成为一项很受欢迎的技术。与传统的基于内容过滤直接分析内容进行 推荐不同,协同过滤分析用户兴趣,在用户群中找到指定用户的相似(兴趣)用 户,综合这些相似用户对某一信息的评价,形成系统对该指定用户对此信息的喜 好程度预测。
    协同过滤是迄今为止最成功的推荐系统技术,被应用在很多成功的推荐系统中。 电子商务推荐系统可根据其他用户的评论信息,采用协同过滤技术给目标用户推 荐商品。

    协同过滤算法

    协同过滤算法主要分为基于启发式基于模型式两种。
    其中,基于启发的协同过滤算法,又可以分为基于用户的协同过滤算法 (User-Based)基于项目的协同过滤算法(Item-Based)
     启发式协同过滤算法主要包含 3 个步骤:
    1)收集用户偏好信息
    2)寻找相似的商品或者用户
    3)产生推荐

    一、基于用户的协同过滤算法

    基于用户的协同过滤算法主要分为两步:
    (1)找到与目标用户兴趣相似的用户集合
    (2)找到这个集合中用户喜欢的、并且目标用户没有听说过的物品推荐给目标用户

    1.相似度的计算方法

    皮尔逊相关系数:
    在这里插入图片描述
    其中,i 表示项,例如商品;Iu 表示用户 u 评价的项集;Iv 表示用户 v 评价的项 集;ru,i 表示用户 u 对项 i 的评分;rv,i 表示用户 v 对项 i 的评分;表示用户 u 的平均评分;表示用户 v 的平均评分。
    余弦相似度
    在这里插入图片描述

    2.计算用户 u 对未评分商品的预测分值

    首先根据上一步中 的相似度计算,寻找用户 u 的邻居集 N∈U,其中 N 表示邻居集,U 表示用户集。 然后,结合用户评分数据集,预测用户 u 对项 i 的评分,计算公式如下所示:
    在这里插入图片描述
    s(u,u’)表示用户 u 和用户 u’的相似度。

    3.通过例子理解

    假设有如下电子商务评分数据集,预测用户 C 对商品 4 的评分。
    在这里插入图片描述
    表中?表示评分未知。根据基于用户的协同过滤算法步骤,计算用户 C 对商品 4 的评分,其步骤如下所示。
    (1)寻找用户 C 的邻居 从数据集中可以发现,只有用户 A 和用户 D 对商品 4 评过分,因此候选邻居只 有 2 个,分别为用户 A 和用户 D。用户 A 的平均评分为 4,用户 C 的平均评分为 3.667,用户 D 的平均评分为3

    在这里插入图片描述
    根据皮尔逊相关系数公式: 红色区域计算 C 用户与 A 用户,用户 C 和用户 A 的相似度为:

    在这里插入图片描述
    蓝色区域计算 C 用户与 D 用户的相似度为:
    在这里插入图片描述
    (2)预测用户 C 对商品 4 的评分 根据上述评分预测公式,计算用户 C 对商品 4 的评分,如下所示:
    在这里插入图片描述

    二、基于项目的协同过滤

    基于物品的协同过滤算法主要分为两步:
    (1)计算物品之间的相似度,通过共现矩阵实现
    (2)根据物品的相似度和用户的历史行为给用户生成推荐列表

    1.相似度计算方法

    在这里插入图片描述分母|N(i)]|是喜欢物品 i 的用户数,|N(i)∩N(j)|是同时喜欢物品 i 和 j 的用户
    计算物品相似度首先建立用户-物品倒排表,根据矩阵计算每两个物品之间的相似度 wij。W[i][j]记录了同时喜欢物品i和物品j的用户数。
    在这里插入图片描述
    得到物品之间的相似度后,可以根据如下公式计算用户 u 对于物品 j 的兴趣
    在这里插入图片描述
    N(u)是用户喜欢的物品的集合,S(j,K)是和物品 j 最相似的 K 个物品的集合, wji 是物品 j 和 i 的相似度,rui 是用户 u 对物品 i 的兴趣。 i 的相似度,rui 是用户 u 对物品 i 的兴趣。(对于隐反馈数据集, 如果用户 u 对物品 i 有过行为,即可令 rui=1。)该公式的含义是,和用户历史 上感兴趣的物品越相似的物品,越有可能在用户的推荐列表中获得比较高的排名。
    该公式的实现代码如下所示:

    def Recommendation(train, user_id, W, K):
    rank = dict()
    ru = train[user_id]
    for i,pi in ru.items():
    for j, wj in sorted(W[i].items(), key=itemgetter(1), reverse=True)[0:K]:
    if j in ru:
    continue
    rank[j] += pi * wj
    return rank
    

    2.通过例子理解:

    现有用户的访问的记录如下图所示:
    在这里插入图片描述
    他的共现矩阵为:
    在这里插入图片描述
    通过公式计算相似度:
    在这里插入图片描述
    以此类推得到相似度的共现矩阵
    在这里插入图片描述
    此时若有新用户 E,访问的 a,b,d 三个物品,那么可以看做向量 P:
    在这里插入图片描述
    在这里插入图片描述

    T为物品的共现矩阵,P为新用户对已有产品的向量,得到的 P`为新用户对每个产品的兴趣度。
    此时得到了对于用户 E,c 和 e 两个物品的兴趣度是相同的。
    理解公式 i∈N(u)∩S(j,K)
    对于用户 E,已经访问了 a,b,d,那么,N(u)={a,b,d};还有两个未访问物品 c,e, 那么 j={c,e}; 当 j=c 时,对于和物品 j 最相似的 K 个物品的集合为{a,d,e},那么 S(j,K)={a,d,e}; 得出N(u)∩S(j,K)={a,d},如下图所示:
    在这里插入图片描述
    再来看矩阵相乘中的 c 行,乘以 P,实际上就是上述 N(u)∩S(j,K)={a,d}的相似度求和
    在这里插入图片描述
    同理,当 j=e 时,对于和物品 j 最相似的 K 个物品的集合为{b,c,d},那么 S(j,K)={b,c,d};得出 N(u)∩S(j,K)={b,d};如下图所示:
    在这里插入图片描述
    再来看矩阵相乘中的 e 行,乘以 P,实际上就是上述 N(u)∩S(j,K)={b,d}的相似度求和。
    在这里插入图片描述

    展开全文
  • 协同滤波

    千次阅读 2018-08-21 16:09:25
    一、什么是协同过滤:人以类聚,物以群分 类似于图像处理中使用超像素信息,协同过滤是利用集体智慧的一个典型方法。推荐系统的首要问题是了解你的用户,然后才能给出更好的推荐。 概念:协同过滤一般是在海量的...

    一、什么是协同过滤:人以类聚,物以群分

    类似于图像处理中使用超像素信息,协同过滤是利用集体智慧的一个典型方法。推荐系统的首要问题是了解你的用户,然后才能给出更好的推荐。

    概念:协同过滤一般是在海量的用户中发掘出一小部分和你品位(偏好)比较类似的,在协同过滤中,这些用户成为邻居,然后根据他们喜欢的其他东西组织成一个排序的目录作为推荐给你。

    核心的问题:

    • 如何确定一个用户是不是和你有相似的品位?
    • 如何将邻居们的喜好组织成一个排序的目录?

    主要的功能:预测和推荐。

    分类:基于用户的协同过滤算法(user-based collaboratIve filtering),和基于物品的协同过滤算法(item-based collaborative filtering)。

    二、协同过滤的基本流程

    首先,要实现协同过滤,需要以下几个步骤

    • 收集用户偏好
    • 找到相似的用户或物品
    • 计算推荐

    1、收集用户偏好

    要从用户的行为和偏好中发现规律,并基于此给予推荐,如何收集用户的偏好信息成为系统推荐效果最基础的决定因素。用户有很多方式向系统提供自己的偏好信息,而且不同的应用也可能大不相同,下面举例进行介绍:

    以上列举的用户行为都是比较通用的,推荐引擎设计人员可以根据自己应用的特点添加特殊的用户行为,并用他们表示用户对物品的喜好。在一般应用中,我们提取的用户行为一般都多于一种,关于如何组合这些不同的用户行为,基本上有以下两种方式:

    • 将不同的行为分组 
      一般可以分为“查看”和“购买”等等,然后基于不同的行为,计算不同的用户 / 物品相似度。类似于当当网或者 Amazon 给出的“购买了该图书的人还购买了 ...”,“查看了图书的人还查看了 ...”

    • 加权操作 
      根据不同行为反映用户喜好的程度将它们进行加权,得到用户对于物品的总体喜好。一般来说,显式的用户反馈比隐式的权值大,但比较稀疏,毕竟进行显示反馈的用户是少数;同时相对于“查看”,“购买”行为反映用户喜好的程度更大,但这也因应用而异。

    收集了用户行为数据,我们还需要对数据进行一定的预处理,其中最核心的工作就是:减噪和归一化。

    • 减噪 
      用户行为数据是用户在使用应用过程中产生的,它可能存在大量的噪音和用户的误操作,我们可以通过经典的数据挖掘算法过滤掉行为数据中的噪音,这样可以是我们的分析更加精确。

    • 归一化 
      如前面讲到的,在计算用户对物品的喜好程度时,可能需要对不同的行为数据进行加权。但可以想象,不同行为的数据取值可能相差很大,比如,用户的查看数据必然比购买数据大的多,如何将各个行为的数据统一在一个相同的取值范围中,从而使得加权求和得到的总体喜好更加精确,就需要我们进行归一化处理。最简单的归一化处理,就是将各类数据除以此类中的最大值,以保证归一化后的数据取值在 [0,1] 范围中。

    进行的预处理后,根据不同应用的行为分析方法,可以选择分组或者加权处理,之后我们可以得到一个用户偏好的二维矩阵,一维是用户列表,另一维是物品列表,值是用户对物品的偏好,一般是 [0,1] 或者 [-1, 1] 的浮点数值。

    2、找到相似的用户或物品

    当已经对用户行为进行分析得到用户喜好后,我们可以根据用户喜好计算相似用户和物品,然后基于相似用户或者物品进行推荐,这就是最典型的 CF 的两个分支:基于用户的 CF 和基于物品的 CF。这两种方法都需要计算相似度,下面我们先看看最基本的几种计算相似度的方法。
    (1)、相似度的计算 
    关于相似度的计算,现有的几种基本方法都是基于向量(Vector)的,其实也就是计算两个向量的距离,距离越近相似度越大。在推荐的场景中,在用户 - 物品偏好的二维矩阵中,我们可以将一个用户对所有物品的偏好作为一个向量来计算用户之间的相似度,或者将所有用户对某个物品的偏好作为一个向量来计算物品之间的相似度。下面我们详细介绍几种常用的相似度计算方法:

    • 欧几里德距离(Euclidean Distance)

    最初用于计算欧几里德空间中两个点的距离,假设 x,y 是 n 维空间的两个点,它们之间的欧几里德距离是: 

    可以看出,当 n=2 时,欧几里德距离就是平面上两个点的距离。 
    当用欧几里德距离表示相似度,一般采用以下公式进行转换:距离越小,相似度越大。 

    • 皮尔逊相关系数(Pearson Correlation Coefficient)

    皮尔逊相关系数一般用于计算两个定距变量间联系的紧密程度,它的取值在 [-1,+1] 之间。 

    sx, sy是 x 和 y 的样品标准偏差。

    • Cosine 相似度(Cosine Similarity)

    Cosine 相似度被广泛应用于计算文档数据的相似度: 

    Tanimoto 系数(Tanimoto Coefficient)

    • Tanimoto 系数

    也称为 Jaccard 系数,是 Cosine 相似度的扩展,也多用于计算文档数据的相似度: 

    2、相似邻居的计算 
    介绍完相似度的计算方法,下面我们看看如何根据相似度找到用户 - 物品的邻居,常用的挑选邻居的原则可以分为两类:图 1 给出了二维平面空间上点集的示意图。 
    图 1 相似邻居计算示意图

    • 固定数量的邻居:K-neighborhoods 或者 Fix-size neighborhoods

    不论邻居的“远近”,只取最近的 K 个,作为其邻居。如图 1 中的 A,假设要计算点 1 的 5- 邻居,那么根据点之间的距离,我们取最近的 5 个点,分别是点 2,点 3,点 4,点 7 和点 5。但很明显我们可以看出,这种方法对于孤立点的计算效果不好,因为要取固定个数的邻居,当它附近没有足够多比较相似的点,就被迫取一些不太相似的点作为邻居,这样就影响了邻居相似的程度,比如图 1 中,点 1 和点 5 其实并不是很相似。

    • 基于相似度门槛的邻居:Threshold-based neighborhoods

    与计算固定数量的邻居的原则不同,基于相似度门槛的邻居计算是对邻居的远近进行最大值的限制,落在以当前点为中心,距离为 K 的区域中的所有点都作为当前点的邻居,这种方法计算得到的邻居个数不确定,但相似度不会出现较大的误差。如图 1 中的 B,从点 1 出发,计算相似度在 K 内的邻居,得到点 2,点 3,点 4 和点 7,这种方法计算出的邻居的相似度程度比前一种优,尤其是对孤立点的处理。

    3、计算推荐

    经过前期的计算已经得到了相邻用户和相邻物品,下面介绍如何基于这些信息为用户进行推荐。

    • 基于用户的 CF(User CF)

    基于用户的 CF 的基本思想相当简单,基于用户对物品的偏好找到相邻邻居用户,然后将邻居用户喜欢的推荐给当前用户。计算上,就是将一个用户对所有物品的偏好作为一个向量来计算用户之间的相似度,找到 K 邻居后,根据邻居的相似度权重以及他们对物品的偏好,预测当前用户没有偏好的未涉及物品,计算得到一个排序的物品列表作为推荐。图 2 给出了一个例子,对于用户 A,根据用户的历史偏好,这里只计算得到一个邻居 - 用户 C,然后将用户 C 喜欢的物品 D推荐给用户 A。
    图 2 基于用户的 CF 的基本原理

    • 基于物品的 CF(Item CF)

    基于物品的 CF 的原理和基于用户的 CF 类似,只是在计算邻居时采用物品本身,而不是从用户的角度,即基于用户对物品的偏好找到相似的物品,然后根据用户的历史偏好,推荐相似的物品给他。从计算的角度看,就是将所有用户对某个物品的偏好作为一个向量来计算物品之间的相似度,得到物品的相似物品后,根据用户历史的偏好预测当前用户还没有表示偏好的物品,计算得到一个排序的物品列表作为推荐。图 3 给出了一个例子,对于物品 A,根据所有用户的历史偏好,喜欢物品 A 的用户都喜欢物品 C,得出物品 A 和物品 C 比较相似,而用户 C 喜欢物品 A,那么可以推断出用户 C 可能也喜欢物品 C。

    图 3 基于物品的 CF 的基本原理 

    4、两种算法的比较

    前面介绍了 User CF 和 Item CF 的基本原理,下面我们分几个不同的角度深入看看它们各自的优缺点和适用场景:

    • 计算复杂度

    Item CF 和 User CF 是基于协同过滤推荐的两个最基本的算法,User CF 是很早以前就提出来了,Item CF 是从 Amazon 的论文和专利发表之后(2001 年左右)开始流行,大家都觉得 Item CF 从性能和复杂度上比 User CF 更优,其中的一个主要原因就是对于一个在线网站,用户的数量往往大大超过物品的数量,同时物品的数据相对稳定,因此计算物品的相似度不但计算量较小,同时也不必频繁更新。但我们往往忽略了这种情况只适应于提供商品的电子商务网站,对于新闻,博客或者微内容的推荐系统,情况往往是相反的,物品的数量是海量的,同时也是更新频繁的,所以单从复杂度的角度,这两个算法在不同的系统中各有优势,推荐引擎的设计者需要根据自己应用的特点选择更加合适的算法。

    • 适用场景

    在非社交网络的网站中,内容内在的联系是很重要的推荐原则,它比基于相似用户的推荐原则更加有效。比如在购书网站上,当你看一本书的时候,推荐引擎会给你推荐相关的书籍,这个推荐的重要性远远超过了网站首页对该用户的综合推荐。可以看到,在这种情况下,Item CF 的推荐成为了引导用户浏览的重要手段。同时 Item CF 便于为推荐做出解释,在一个非社交网络的网站中,给某个用户推荐一本书,同时给出的解释是某某和你有相似兴趣的人也看了这本书,这很难让用户信服,因为用户可能根本不认识那个人;但如果解释说是因为这本书和你以前看的某本书相似,用户可能就觉得合理而采纳了此推荐。相反的,在现今很流行的社交网络站点中,User CF 是一个更不错的选择,User CF 加上社会网络信息,可以增加用户对推荐解释的信服程度。

    • 推荐多样性和精度

    研究推荐引擎的学者们在相同的数据集合上分别用 User CF 和 Item CF 计算推荐结果,发现推荐列表中,只有 50% 是一样的,还有 50% 完全不同。但是这两个算法确有相似的精度,所以可以说,这两个算法是很互补的。
    关于推荐的多样性,有两种度量方法: 
    第一种度量方法是从单个用户的角度度量,就是说给定一个用户,查看系统给出的推荐列表是否多样,也就是要比较推荐列表中的物品之间两两的相似度,不难想到,对这种度量方法,Item CF 的多样性显然不如 User CF 的好,因为 Item CF 的推荐就是和以前看的东西最相似的。
    第二种度量方法是考虑系统的多样性,也被称为覆盖率 (Coverage),它是指一个推荐系统是否能够提供给所有用户丰富的选择。在这种指标下,Item CF 的多样性要远远好于 User CF, 因为 User CF 总是倾向于推荐热门的,从另一个侧面看,也就是说,Item CF 的推荐有很好的新颖性,很擅长推荐长尾里的物品。所以,尽管大多数情况,Item CF 的精度略小于 User CF, 但如果考虑多样性,Item CF 却比 User CF 好很多。
    如果你对推荐的多样性还心存疑惑,那么下面我们再举个实例看看 User CF 和 Item CF 的多样性到底有什么差别。首先,假设每个用户兴趣爱好都是广泛的,喜欢好几个领域的东西,不过每个用户肯定也有一个主要的领域,对这个领域会比其他领域更加关心。给定一个用户,假设他喜欢 3 个领域 A,B,C,A 是他喜欢的主要领域,这个时候我们来看 User CF 和 Item CF 倾向于做出什么推荐:如果用 User CF, 它会将 A,B,C 三个领域中比较热门的东西推荐给用户;而如果用 ItemCF,它会基本上只推荐 A 领域的东西给用户。所以我们看到因为 User CF 只推荐热门的,所以它在推荐长尾里项目方面的能力不足;而 Item CF 只推荐 A 领域给用户,这样他有限的推荐列表中就可能包含了一定数量的不热门的长尾物品,同时 Item CF 的推荐对这个用户而言,显然多样性不足。但是对整个系统而言,因为不同的用户的主要兴趣点不同,所以系统的覆盖率会比较好。

    • 总结

    从上面的分析,可以很清晰的看到,这两种推荐都有其合理性,但都不是最好的选择,因此他们的精度也会有损失。其实对这类系统的最好选择是,如果系统给这个用户推荐 30 个物品,既不是每个领域挑选 10 个最热门的给他,也不是推荐 30 个 A 领域的给他,而是比如推荐 15 个 A 领域的给他,剩下的 15 个从 B,C 中选择。所以结合 User CF 和 Item CF 是最优的选择,结合的基本原则就是当采用 Item CF 导致系统对个人推荐的多样性不足时,我们通过加入 User CF 增加个人推荐的多样性,从而提高精度,而当因为采用 User CF 而使系统的整体多样性不足时,我们可以通过加入 Item CF 增加整体的多样性,同样同样可以提高推荐的精度。

    • 用户对推荐算法的适应度

    前面我们大部分都是从推荐引擎的角度考虑哪个算法更优,但其实我们更多的应该考虑作为推荐引擎的最终使用者 -- 应用用户对推荐算法的适应度。 
    对于 User CF,推荐的原则是假设用户会喜欢那些和他有相同喜好的用户喜欢的东西,但如果一个用户没有相同喜好的朋友,那 User CF 的算法的效果就会很差,所以一个用户对的 CF 算法的适应度是和他有多少共同喜好用户成正比的。
    Item CF 算法也有一个基本假设,就是用户会喜欢和他以前喜欢的东西相似的东西,那么我们可以计算一个用户喜欢的物品的自相似度。一个用户喜欢物品的自相似度大,就说明他喜欢的东西都是比较相似的,也就是说他比较符合 Item CF 方法的基本假设,那么他对 Item CF 的适应度自然比较好;反之,如果自相似度小,就说明这个用户的喜好习惯并不满足 Item CF 方法的基本假设,那么对于这种用户,用 Item CF 方法做出好的推荐的可能性非常低。

    四、实例演示

    1、基于用户的协同过滤算法

    基于用户的协同过滤算法是通过用户的历史行为数据发现用户对商品或内容的喜欢(如商品购买,收藏,内容评论或分享),并对这些喜好进行度量和打分。根据不同用户对相同商品或内容的态度和偏好程度计算用户之间的关系。在有相同喜好的用户间进行商品推荐。简单的说就是如果A,B两个用户都购买了x,y,z三本图书,并且给出了5星的好评。那么A和B就属于同一类用户。可以将A看过的图书w也推荐给用户B。

    • 寻找偏好相似的用户

    我们模拟了5个用户对两件商品的评分,来说明如何通过用户对不同商品的态度和偏好寻找相似的用户。在示例中,5个用户分别对两件商品进行了评分。这里的分值可能表示真实的购买,也可以是用户对商品不同行为的量化指标。例如,浏览商品的次数,向朋友推荐商品,收藏,分享,或评论等等。这些行为都可以表示用户对商品的态度和偏好程度。

    从表格中很难直观发现5个用户间的联系,我们将5个用户对两件商品的评分用散点图表示出来后,用户间的关系就很容易发现了。在散点图中,Y轴是商品1的评分,X轴是商品2的评分,通过用户的分布情况可以发现,A,C,D三个用户距离较近。用户A(3.3 6.5)和用户C(3.6 6.3),用户D(3.4 5.8)对两件商品的评分较为接近。而用户E和用户B则形成了另一个群体。

    散点图虽然直观,但无法投入实际的应用,也不能准确的度量用户间的关系。因此我们需要通过数字对用户的关系进行准确的度量,并依据这些关系完成商品的推荐。

    • 欧几里德距离评价

    欧几里德距离评价是一个较为简单的用户关系评价方法。原理是通过计算两个用户在散点图中的距离来判断不同的用户是否有相同的偏好。公式参考上面的介绍。 
    通过公式我们获得了5个用户相互间的欧几里德系数,也就是用户间的距离。系数越小表示两个用户间的距离越近,偏好也越是接近。不过这里有个问题,太小的数值可能无法准确的表现出不同用户间距离的差异,因此我们对求得的系数取倒数,使用户间的距离约接近,数值越大。在下面的表格中,可以发现,用户A&C用户A&D和用户C&D距离较近。同时用户B&E的距离也较为接近。与我们前面在散点图中看到的情况一致。

    • 皮尔逊相关度评价

    皮尔逊相关度评价是另一种计算用户间关系的方法。他比欧几里德距离评价的计算要复杂一些,但对于评分数据不规范时皮尔逊相关度评价能够给出更好的结果。以下是一个多用户对多个商品进行评分的示例。这个示例比之前的两个商品的情况要复杂一些,但也更接近真实的情况。我们通过皮尔逊相关度评价对用户进行分组,并推荐商品。

    这里我们使用用户评分数据如下:其中P1-P5表示五个用户,A-F表示六个商品。

    • 皮尔逊相关系数

    皮尔逊相关系数的计算公式参考上面介绍,结果是一个在-1与1之间的系数。该系数用来说明两个用户间联系的强弱程度。 假如我们需要给P5用户推荐东西,那么我们需要计算P5和P1-4的皮尔逊相关系数。计算结果如下:

     

    
     
    1. p5与p4之间的相关系数:0.3674234614174766

    2. p5与p3之间的相关系数:0.9185586535436919

    3. p5与p2之间的相关系数:0.6605782590758166

    4. p5与p1之间的相关系数:0.43915503282684004



     

     

    • 为相似的用户提供推荐物品

    目前我们得到的数据情况如下:我们需要为P5推荐三部电影中的一部,有直接推荐和加权排序推荐两种方法。

    直接推荐:假如我们需要为用户P5推荐电影,首先我们检查相似度列表,发现用户P5和用户P3的相似度最高。因此,我们可以对用户P5推荐P3的相关数据。但这里有一个问题。我们不能直接推荐前面A-F的商品。因为这这些商品用户P5已经浏览或者购买过了。不能重复推荐。因此我们要推荐用户P5还没有浏览或购买过的商品。如果直接推荐我们可以选择P3用户评价最高的商品,也就是环太平洋和变形金刚两个数据。

    加权排序推荐:我们根据不同用户间的相似度,对不同商品的评分进行相似度加权。按加权后的结果对商品进行排序,然后推荐给用户P5。这样,用户P5就获得了更好的推荐结果。

    上面的计算结果中,我们按照(变形金刚--环太平洋--玩命速递)的顺序把结果推荐给用户P5。

    以上是基于用户的协同过滤算法。这个算法依靠用户的历史行为数据来计算相关度。也就是说必须要有一定的数据积累(冷启动问题)。对于新网站或数据量较少的网站,还有一种方法是基于物品的协同过滤算法。

    展开全文
  • Python分析和实现基于用户和Item的协同过滤算法

    万次阅读 多人点赞 2016-05-30 12:08:02
    打开微信扫一扫,关注...1:协同过滤算法简介 2:协同过滤算法的核心 3:协同过滤算法的应用方式 4:基于用户的协同过滤算法实现 5:基于物品的协同过滤算法实现 一:协同过滤算法简介 关于协同过滤的...
  • 云边协同协同的类型

    千次阅读 热门讨论 2020-10-31 21:15:32
    文章目录目录边缘计算与云计算的区别边缘计算的关键优势云边协同 边缘计算与云计算的区别 计算的形态跟网络的成本息息相关,计算分布形态就是数据在网络中传输成本和计算收益之间形成动态平衡。 云计算基于大量集中...
  • 协同过滤(Collaborative Filtering)技术,是推荐系统中应用最为广泛的技术之一,协同过滤算法主要有两种,一种是基于用户的协同过滤算法(UserBaseCF),另一种是基于物品的协同过滤算法(ItemBaseCF)。 基于用户...
  • 使用github进行协同开发

    千次阅读 多人点赞 2020-05-03 14:04:26
    github协同开发准备工作fork仓库clone到本地添加远端仓库地址对本地代码进行更新(同步远程仓库代码)创建分支在分支上进行提交合并分支 准备工作 如果你一直是自己一个人开发,每次的操作都是add commit push,如果...
  • Unity协同

    2016-06-09 14:19:00
    协同注意事项: 1.协同的返回值类型必须是IEnumerator 2.协同的参数不能加关键字ref或者out 3.在c#脚本中必须使用StartCoroutine来启动协同 4.yield语句要用yield return来代替 5.在函数Update和FixedUpdate中不能...
  • 基于近邻的协同过滤算法

    千次阅读 多人点赞 2021-03-12 15:49:09
    基于近邻用户的协同过滤 假定有一个场景:某个周日的下午,你感觉很无聊,然后从电脑上打开了一个视频网站,想看下最近有什么好看的电影。然而你发现网站上的热门电影基本都看过,其他的电影又太多,不知道该看什么...
  • 协同程序

    千次阅读 2014-02-24 17:54:38
    1. 什么是协同程序  在主程序运行时同时开启另一段逻辑处理,来协同当前程序的执行。换句话说,开启协同程序就是开启一个线程。   2. 协同程序的开启与终止  在Unity3D中,使用MonoBehaviour....
  • 推荐系统-经典协同过滤理论基础实践 1.协同过滤推荐方法CF简介 协同过滤CF 基于记忆的协同过滤 ---- 用户和物品的相似度矩阵 用户相似度的推荐 物品相似度推荐 UserCF用户协同过滤算法 ItemCF物品的协同过滤推荐...
  • U8多组织协同方案、业务协同方案

    千次阅读 2018-03-20 17:46:57
    U8多组织协同方案、业务协同方案 欢迎交流学习,本人QQ:304418200 产品开源地址 GIT https://github.com/moniterniu/LxzLib
  • 协同过滤算法

    2017-07-11 17:33:19
    在现今的推荐技术和算法中,最被大家广泛认可和采用的就是基于协同过滤的推荐方法。本文将带你深入了解协同过滤的秘密。下面直接进入正题1 什么是协同过滤协同过滤是利用集体智慧的一个典型方法。要理解什么是协同...
  • 协同过滤算法源码

    热门讨论 2011-12-12 16:34:45
    基于项目(Item-based)协同过滤算法源码 可用于个性化推荐 参加卓越亚马逊商品推荐
  • 协同进化

    千次阅读 2018-11-22 21:46:18
    协同进化的第一个应用,是用于进化IPD策略和进化排序算法。IPD是Integrated Product Development缩写,中文直译为“集成产品开发”。后又被用于其他复杂实际问题。 零和游戏:指参与博弈的各方,在严格竞争下,一方...
  • 协同开发

    千次阅读 2016-11-16 08:01:31
    同一个开发项目中如果有多名程序猿,那么每个程序猿都有责任培养自己协同开发的意识,为的是代码的质量,质量,质量(重要的事情说三遍!!!)。协同开发是个挖坑和填坑的过程,自己做的好可以尽量避免自己挖坑,还...
  • 1.1.协同过滤 协同过滤是目前应用最广泛的推荐算法,它仅仅通过了解用户与物品之间的关系进行推荐,而根本不会考虑到物品本身的属性。 可分成两类: 1、基于用户(user-based)的协同过滤 2、基于商品(item-...
  • 协同过滤推荐算法详解

    万次阅读 多人点赞 2017-07-07 20:39:44
    一、什么是协同过滤? 协同过滤是利用集体智慧的一个典型方法。要理解什么是协同过滤 (Collaborative Filtering, 简称 CF),首先想一个简单的问题,如果你现在想看个电影,但你不知道具体看哪部,你会怎么做?大部分...
  • 推荐引擎算法学习导论:协同过滤、聚类、分类 作者:July 出处:结构之法算法之道 引言 昨日看到几个关键词:语义分析,协同过滤,智能推荐,想着想着便兴奋了。于是昨天下午开始到今天凌晨3点,便研究了...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 299,668
精华内容 119,867
关键字:

协同