个性化推荐学习(mahout)

参考链接:个性化推荐算法总结:https://blog.csdn.net/Yasin0/article/details/89222622
Mahout 详解:https://blog.csdn.net/qq_36864672/article/details/78796295
用Maven构建Mahout项目:http://blog.fens.me/hadoop-mahout-maven-eclipse/
推荐系统算法实战(协同过滤CF算法):https://blog.csdn.net/universsky2015/article/details/103679861
mahout推荐6DataModel:https://www.cnblogs.com/jsunday/p/3889619.html
尚硅谷大数据教育之机器学习和推荐系统
mahout连接mysql,使用ReloadFromJDBCDataModel,采用SVD推荐算法:https://blog.csdn.net/pan12jian/article/details/26451495
Mahout中数据的存储方式:https://my.oschina.net/xiaominmin/blog/1599459

1 简单介绍

推荐看个性化推荐算法总结(还挺详细的,好像是推荐系统实战这本书上的)
在这里插入图片描述

1.2 推荐系统评测

在这里插入图片描述

2 Mahout

2.1 简介

用Mahout来构建推荐系统,是一件既简单又困难的事情。简单是因为Mahout完整地封装了“协同过滤”算法,并实现了并行化,提供非常简单的API接口;困难是因为我们不了解算法细节,很难去根据业务的场景进行算法配置和调优。
在这里插入图片描述

2.2 Maven Repository(使用maven构建mahout项目)

<dependency>
			<groupId>org.apache.mahout</groupId>
			<artifactId>mahout-core</artifactId>
			<version>${mahout.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.mahout</groupId>
			<artifactId>mahout-math</artifactId>
			<version>${mahout.version}</version>			
		</dependency>		
		<dependency>
			<groupId>org.apache.mahout</groupId>
			<artifactId>mahout-integration</artifactId>
			<version>${mahout.version}</version>
			<exclusions>
				<exclusion>
					<groupId>org.mortbay.jetty</groupId>
					<artifactId>jetty</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.apache.cassandra</groupId>
					<artifactId>cassandra-all</artifactId>
				</exclusion>
				<exclusion>
					<groupId>me.prettyprint</groupId>
					<artifactId>hector-core</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

2.3 使用mahout实现推荐功能

Mahout中和推荐系统相关内容有四个部分:
Preference类: 表示每个用户或者物品的属性, 如{1: {2: 1.0, 3: 2.0}} 表示用户2和3分别对1进行了评价, 评分分别为1.0和2.0
DataModel类: 表示所有的数据集合, 即Preference的聚合. DataModel可以是代码输入或者HTTP参数获取, 也可以从文件或者数据库中读取.
Similarity类: 表示所有Preference两者之间的相似度, 所有的用户或者物品都通过Similarty建立起了联系, 所以这个是非常重要的, Similarity的选择和数据的类型有很大关系. Neighberhood记录每个用户或者物品相似的物品集, 方便后期调用.
Recommender类: 表示推荐算法, 整个系统的核心。 如何使用前面的Preference, DataModel, Similarity以及Neigherhood都将结合在Recommender来来使用。
在这里插入图片描述一个优秀的推荐系统由以下五个部分构成:
1. 高质量和高数量的数据. Garbage in, Garbage out.
2. 高效存储的数据结构以及高效的数学运算库
3. 优秀的算法架构和调参技术
4. 优秀的架构设计, 防止数据的多次拷贝, 并且利于数据的更新和一致性.
5. 优秀的用户体验和人机交互设计

2.3.1 userbasedCF(基于用户的协同过滤)

用户A喜欢物品1、2、3、4、5、6、7、8
用户B喜欢物品1、2、3、4、5、6、7
用户A和B喜欢的东西很相似,所以用户A喜欢的东西,用户B也可能喜欢
故用户A喜欢物品8,向用户B也推荐物品8
在这里插入图片描述

基于用户的协同过滤算法思路:分为三步,分别是①建立用户矩阵模型;②通过用户相似度寻找最近邻居;③产生推荐项目。

/*
 * 基本的过程(步骤)
 * 1.分析各个用户(user)对物品(item)的评分
 * 2.根据用户对物品的评分,计算所有用户之间的相似度(余弦相似度、欧式距离等等)
 * 3.选出与当前用户最相似的N个用户
 * 4.将当前用户购买过的商品,推荐给其他用户:反之也行
 */
public class UserBasedCF {
    final static int NEIGHBORHOOD_NUM = 2;
    final static int RECOMMENDER_NUM = 3;

    public static void main(String[] args) throws Exception {
        //根据数据源建立数据模型,即:打分矩阵
        String file = "D:\\download\\data\\ratingdata.txt";
//1. 创建模型        
        DataModel model = new FileDataModel(new File(file));
//2. 创建 UserSimilarity 对象
        //根据打分矩阵,计算用户的相似度
        UserSimilarity usersimilarity = new EuclideanDistanceSimilarity(model);
//3. 创建 NearestNUserNeighborhood 对象 例:Neighborhood
        //找到与用户相近的邻居,即:找到NEIGHBORHOOD_NUM的相邻用户
        //n:找到相似的N个用户
        NearestNUserNeighborhood neighbor = new NearestNUserNeighborhood(NEIGHBORHOOD_NUM, usersimilarity, model);
//4. 创建推荐器对象 例:UserBasedRecommender
        // 构建基于用户的推荐引擎,其中dataModel为数据模型,neighborhood为用户领域模型,usersimilarity为相似度模型
        Recommender r = new GenericUserBasedRecommender(model, neighbor, usersimilarity);

        System.out.println("***************测试一:给一个用户推荐****************");
//5. 推荐商品给用户
        //向用户1推荐两个商品  说明:recommender.recommend(userID, howMany)
        List<RecommendedItem> recommendations = r.recommend(1, 2);
        for (RecommendedItem recommendation : recommendations) {
            // 输出推荐结果
            System.out.println("给用户1推荐的商品是:" + recommendation.getItemID());
        }

        System.out.println("***************测试二:给每个用户都推荐****************");
        //向每个用户推荐商品
        LongPrimitiveIterator iter = model.getUserIDs();
        while (iter.hasNext()) {
            long uid = iter.nextLong();
            System.out.printf("用户ID:%s  ", uid);

            List<RecommendedItem> list = r.recommend(uid, RECOMMENDER_NUM);
            for (RecommendedItem ritem : list) {
                System.out.printf("(%s,%f)", ritem.getItemID(), ritem.getValue());
            }
            System.out.println();
        }
    }
}

2.3.2 itembasedCF(基于商品的协同过滤)

喜欢物品1的人,例如用户A、B、…,发现他们也都喜欢物品2
说明一般喜欢物品1的人,也喜欢物品2
故用户C喜欢物品1,那么他可能也会喜欢物品2
故向用户C推荐物品2

在这里插入图片描述

public class ItemBasedCF {
	public static void main(String[] args) throws IOException, TasteException {
		//读入(用户-物品-评分)数据,建立打分矩阵
		String file = "D:\\download\\data\\ratingdata.txt";
		DataModel dataModel = new FileDataModel(new File(file));
		//计算物品的相似度矩阵
		ItemSimilarity itemSimilarity=new  EuclideanDistanceSimilarity(dataModel);
		Recommender r=new GenericItemBasedRecommender(dataModel, itemSimilarity);
		
		LongPrimitiveIterator iter=dataModel.getUserIDs();
		while(iter.hasNext()){
			long uid=iter.nextLong();
			List<RecommendedItem> list=r.recommend(uid, 3);

			System.out.println();
			for (RecommendedItem item : list) {
				System.out.println(""+item.getItemID());

			}
			System.out.println("******");
		}
	}

}

在这里插入图片描述

2.3.3 datamodel从数据库中读取

将这两行

//		String file = "D:\\Code\。。。。\\test.csv";
//		DataModel dataModel = new FileDataModel(new File(file));

换成:

MysqlDataSource dataSource =new com.mysql.cj.jdbc.MysqlDataSource();
		dataSource.setServerName("localhost");
		dataSource.setUser( "root");
		dataSource.setPassword( "123");
		dataSource.setDatabaseName( "kss" );

//MySQLJDBCDataModel(DataSource dataSource, String preferenceTable,String userIDColumn,String itemIDColumn,String preferenceColumn,String timestampColumn)
		JDBCDataModel jdbcDataModel= new MySQLJDBCDataModel(dataSource, comTable, uId, iId, rateId, time);
		//利用ReloadFromJDBCDataModel包裹jdbcDataModel,可以把输入加入内存计算,加快计算速度。
		ReloadFromJDBCDataModel dataModel = new ReloadFromJDBCDataModel(jdbcDataModel);
	//这里的refresh是刷新dataModel,一般情况下我觉得用不上,因为像我这个程序,每次都会新建立datamodel,都是最新的,所以不用刷新
		//当然,如果你需要在内存中存储下dataModel,然后自己的taste_preferences时刻在变化,此时是需要刷新的。
		//model.refresh(null);

注意:
1、去掉scope

<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
<!--      <scope>runtime</scope>-->
 </dependency>

2、如果项目中还有其他需要的包,注意包冲突
3、如果报错The server time zone value ‘�й���׼ʱ��’ is unrecognized or represents more than one time zone(服务器时区值’�й���׼ʱ��’ 无法识别或表示多个时区)
在mysql中

set global time_zone = '+8:00';

在这里插入图片描述

2.4 聚类

在这里插入图片描述

用Mahout实现kmeans

public class Kmeans {
    public static void main(String[] args) throws IOException {
        List sampleData = MathUtil.readFileToVector("datafile/randomData.csv");
        int k = 3;
        double threshold = 0.01;
        
        List randomPoints = MathUtil.chooseRandomPoints(sampleData, k);
        for (Vector vector : randomPoints) {
            System.out.println("Init Point center: " + vector);
        }
        List clusters = new ArrayList();
        for (int i = 0; i < k; i++) {
            clusters.add(new Cluster(randomPoints.get(i), i, new EuclideanDistanceMeasure()));
        }

        List<List> finalClusters = KMeansClusterer.clusterPoints(sampleData, clusters, new EuclideanDistanceMeasure(), k, threshold);
        for (Cluster cluster : finalClusters.get(finalClusters.size() - 1)) {
            System.out.println("Cluster id: " + cluster.getId() + " center: " + cluster.getCenter().asFormatString());
        }
    }

}

2.5 分类

在这里插入图片描述

2.6 算法评判标准:召回率(recall)与查准率(precision)

2.7 Recommender的API接口

2.7.1 org.apache.mahout.cf.taste.recommender.Recommender.java

在这里插入图片描述

接口中方法的解释:

recommend(long userID, int howMany): 获得推荐结果,给userID推荐howMany个Item
recommend(long userID, int howMany, IDRescorer rescorer): 获得推荐结果,给userID推荐howMany个Item,可以根据rescorer对结构重新排序。
estimatePreference(long userID, long itemID): 当打分为空,估计用户对物品的打分
setPreference(long userID, long itemID, float value): 赋值用户,物品,打分
removePreference(long userID, long itemID): 删除用户对物品的打分
getDataModel(): 提取推荐数据

通过Recommender接口,我可以猜出核心算法,应该会在子类的estimatePreference()方法中进行实现。

2.7.2 通过继承关系到Recommender接口的子类

在这里插入图片描述推荐算法实现类:

GenericUserBasedRecommender: 基于用户的推荐算法
GenericItemBasedRecommender: 基于物品的推荐算法
KnnItemBasedRecommender: 基于物品的KNN推荐算法
SlopeOneRecommender: Slope推荐算法
SVDRecommender: SVD推荐算法
TreeClusteringRecommender:TreeCluster推荐算法

在这里插入图片描述

2.8 mahaout计算相似度的组件

在这里插入图片描述下面就几个重点相似度计算方法做介绍:

2.8.1 皮尔森相关度

类名:PearsonCorrelationSimilarity

2.8.2 欧式距离相似度

类名:EuclideanDistanceSimilarity

2.8.3 余弦相似度

类名:PearsonCorrelationSimilarity和UncenteredCosineSimilarity

2.8.4 Spearman秩相关系数

类名:SpearmanCorrelationSimilarity
原理:Spearman秩相关系数通常被认为是排列后的变量之间的Pearson线性相关系数。
范围:{-1.0,1.0},当一致时为1.0,不一致时为-1.0。
说明:计算非常慢,有大量排序。针对推荐系统中的数据集来讲,用Spearman秩相关系数作为相似度量是不合适的。

2.8.5 曼哈顿距离

类名:CityBlockSimilarity
原理:曼哈顿距离的实现,同欧式距离相似,都是用于多维数据空间距离的测度
范围:[0,1],同欧式距离一致,值越小,说明距离值越大,相似度越大。
说明:比欧式距离计算量少,性能相对高。

2.8.6 Tanimoto系数

类名:TanimotoCoefficientSimilarity
原理:又名广义Jaccard系数,是对Jaccard系数的扩展,等式为
范围:[0,1],完全重叠时为1,无重叠项时为0,越接近1说明越相似。
说明:处理无打分的偏好数据。

2.8.7 对数似然相似度

类名:LogLikelihoodSimilarity
原理:重叠的个数,不重叠的个数,都没有的个数
范围:具体可去百度文库中查找论文《Accurate Methods for the Statistics of Surprise and Coincidence》
说明:处理无打分的偏好数据,比Tanimoto系数的计算方法更为智能。

2.9 DataModel

import org.apache.mahout.cf.taste.model.DataModel;

要做推荐,用户行为数据是基础。
用户行为数据有哪些字段呢?
mahout的DataModel支持,用户ID,ItemID是必须的,偏好值(用户对当前Item的评分),时间戳 这四个字段

{@code userID, itemID [,preference[,timestamp]]}

Mahout中提供给用户存储结构化数据的类:

 Class FileDataModel: 读取一个有分隔符的数据文件,分隔符仅支持tab和逗号(comma)。 
 		DataModel dataModel = new FileDataModel(new File(file));
 数据格式: userID,itemID[,preference[,timestamp]]
 【要求:数据必须是2列或者4列;所有数据格式必须一致, 即分隔符数量一致;超过4列的数据, 空行以及以'#'开头的数据都会被忽略。】
 示例:如123,456或者123,456,3,129050099059 或者123,456,,129050099059。
 如果一个人只是看过某部电影, 则没有preference项, timestamp表示时间戳.  
 格式:preference自动解析为double类型; userID和itemID解析为longs类型, timestamp自动解析为longs, 但是可以通过重写readTimestampFromString(String)方法来自己解析.
 自定义读取方法: 重写processLine和 processLineWithoutID(String, FastByIDMap, FastByIDMap)
 文件格式:FileDataModel可以读取.zip和.gz格式的压缩包数据。

 Class MysqlJDBCModel: 读取数据库中的数据, 为了提升数据查询效率. userID和itemID不能为空, 两者均需要建立索引, 主键primary key为userID和itemID的composition. 在Mysql中, 需要使用BIGINT和FLOAT类型, 调整buffer和查询cache的大小, Mysql的Connector/J driver中的cachePreparedStatements需要设置为true.

 Class FileIDMigrator: 专门用于读取一系列的字符串并生成相应的MD5标识码在一个FastByIDMap(类似于Java SE中的HashMap中, 用途暂时不明确. 例如数据是一个电影名列表, 文件每行只有一个电影名, 那么FileIDMigrator将生成对应的MD5码。

源码中的数据存储均由GenericDataModel和GenericBooleanPrefDataModel来存储

它们提供一下的比较重要的方法:
getUserIDs: 获取所有用户的ID
getPreferencesFromUser: 获取某个用户对所有物品的评分.
getItemIDsFromUser: 获取某个用户评论过的所有物品.
getItemIDs: 获取所有物品的ID.
getPreferencesForItem: 获取某个物品的所有评分.
getPreferenceValue: 获取某个用户对某个物品的评分.
getPreferenceTime: 获取某个用户对某个物品的评分时间.
getNumItems: 获取所有的物品总数
getNumUsers: 获取所有的用户综述.
getNumUsersWithPreferenceFor 1 item 获取对某个item评论过的用户数目.
getNumUsersWithPreferenceFor 2 items 获取对两个items同时评论过的用户数目.
hasPreferenceValues: 判断是否有评分, 用于区分BooleanDataModel.
getMaxPreference: 最大评分
getMinPreference: 最小评分
setPreference 改变某个用户对某个物品的评分, 并不改变数据源的数据.
removePreference 去除某个用户对某个物品的评分, 并不改变数据源的数据.  

RecommendedItem

public interface RecommendedItem {
  
  /** @return the recommended item ID */
  long getItemID();
  
  /**
   * <p>
   * A value expressing the strength of the preference for the recommended item. The range of the values
   * depends on the implementation. Implementations must use larger values to express stronger preference.
   * </p>
   * 
   * @return strength of the preference
   */
  float getValue();

}

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weightOneMillion

感谢看官们的供粮~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值