持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情
1、前言
上一篇为大家介绍了Mahout开发中Service层的一些示例代码。本次继续为大家介绍另一大部分,推荐器的示例代码。
2、Recommender构造器
这里以基于用户的推荐构造器为例:
/**
* @Title: ItemBasedRecommenderBuilder
* @Description: 基于用户的推荐 Recommender 构造器
*/
public class UserBasedRecommenderBuilder implements RecommenderBuilder {
/**
* 相似度
*/
private UserSimilarity userSimilarity;
/**
* 邻域
*/
private UserNeighborhood userNeighborhood;
/**
* 邻居个数,默认10
*/
private int neighborhoodNumber;
public UserBasedRecommenderBuilder() {
}
public UserBasedRecommenderBuilder(DataModel dataModel, final int neighborhoodNumber) throws TasteException {
// 邻居个数,默认10
this.neighborhoodNumber = neighborhoodNumber;
//相似度矩阵、邻居用户采用默认实现
this.userSimilarity = new PearsonCorrelationSimilarity(dataModel);
this.userNeighborhood = new NearestNUserNeighborhood(neighborhoodNumber, this.userSimilarity, dataModel);
}
@Override
public Recommender buildRecommender(DataModel dataModel) throws TasteException {
return new CachingRecommender(new GenericUserBasedRecommender(dataModel, userNeighborhood, userSimilarity));
}
}
3、定义Recommender接口
定义一个统一的Recommender接口,包括推荐、查准率、查全率等方法。
/**
* @Title: IRecommender
* @Description: IRecommender
* @Company: huayi
*/
public interface IRecommender extends Recommender {
/**
* 采用默认的紧邻计算,推荐默认条数据
* @param userId
* @return
* @throws TasteException
*/
List<RecommendedItem> recommend(final long userId) throws TasteException;
/**
* 计算评分、评估推荐引擎的准确性
* @return
* @throws TasteException
*/
double evaluateScore() throws TasteException;
/**
* 计算评分
* @param recommenderBuilder
* @param dataModel
* @param trainingPercentage
* @param evaluationPercentage
* @return
* @throws TasteException
*/
double evaluateScore(RecommenderBuilder recommenderBuilder, DataModel dataModel,
double trainingPercentage, double evaluationPercentage) throws TasteException;
/**
* 计算查全率、查准率等
* @return
* @throws TasteException
*/
IRStatistics evaluateIRStatistics() throws TasteException;
/**
* 计算查全率和查准率
* @param recommenderBuilder
* @param dataModel
* @param rescorer
* @param at
* @param relevanceThreshold
* @param evaluationPercentage
* @return
* @throws TasteException
*/
IRStatistics evaluateIRStatistics(RecommenderBuilder recommenderBuilder,
DataModel dataModel,
IDRescorer rescorer,
int at,
double relevanceThreshold,
double evaluationPercentage) throws TasteException;
}
4、定义抽象Recommender
抽象Recommender包括共通的评分、查全率、查准率方法的实现。
/**
* @Title: AbstractRecommender
* @Description: 抽象 Recommender 类
*/
public abstract class AbstractRecommender implements IRecommender {
/**
* Recommender构造器
*/
protected RecommenderBuilder recommenderBuilder;
/**
* recommender
*/
protected Recommender recommender;
/**
* 数据模型
*/
protected DataModel dataModel;
@Override
public double evaluateScore() throws TasteException {
return RecommendeEvaluator.evaluateScore(recommenderBuilder, dataModel);
}
@Override
public double evaluateScore(RecommenderBuilder recommenderBuilder, DataModel dataModel,
double trainingPercentage, double evaluationPercentage) throws TasteException {
return RecommendeEvaluator.evaluateScore(recommenderBuilder, dataModel, trainingPercentage,
evaluationPercentage);
}
@Override
public IRStatistics evaluateIRStatistics() throws TasteException {
return RecommendeEvaluator.evaluateIRStatistics(recommenderBuilder, dataModel);
}
/**
* 计算查全率和查准率
* @param recommenderBuilder 推荐算法构造器
* @param dataModel 数据模型
* @param rescorer 如果有的话,在计算推荐时使用
* @param at 如,“精确度为5”。评估精度时要考虑的建议数量,
* @param relevanceThreshold 优先值至少为该值的项目被认为是“相关的”用于计算的目的
* @param evaluationPercentage 评估百分比
* @return
* @throws TasteException
*/
@Override
public IRStatistics evaluateIRStatistics(RecommenderBuilder recommenderBuilder,
DataModel dataModel,
IDRescorer rescorer,
int at,
double relevanceThreshold,
double evaluationPercentage) throws TasteException {
return RecommendeEvaluator.evaluateIRStatistics(
recommenderBuilder, dataModel, rescorer, at, relevanceThreshold, evaluationPercentage);
}
}
5、定义Recommender实现类
这里还是以基于用户的推荐为例。
/**
* @Title: UserBasedCfRecommender
* @Description: 基于用户的推荐 Recommender 类
*/
public class UserBasedCfRecommender extends AbstractRecommender {
public UserBasedCfRecommender() {
}
/**
* UserBasedCFRecommender
* @param dataModel
* @throws TasteException
*/
public UserBasedCfRecommender(final DataModel dataModel) throws TasteException {
defaultInit(dataModel, NumericConstant.TWENTY);
}
/**
* 默认初始化方法
* @param dataModel 数据模型
* @param neighborhoodNumber 邻居个数
* @throws TasteException
*/
private void defaultInit(final DataModel dataModel, final int neighborhoodNumber) throws TasteException {
this.dataModel = dataModel;
this.recommenderBuilder = new UserBasedRecommenderBuilder(dataModel, neighborhoodNumber);
this.recommender = recommenderBuilder.buildRecommender(this.dataModel);
}
/**
* UserBasedCFRecommender
* @param dataModel --数据源
* @param neighborhoodNumber --邻域
* @throws TasteException
*/
public UserBasedCfRecommender(DataModel dataModel, final int neighborhoodNumber) throws TasteException {
defaultInit(dataModel, neighborhoodNumber);
}
@Override
public List<RecommendedItem> recommend(final long userId) throws TasteException {
//默认推荐1条数据
return this.recommend(userId, NumericConstant.ONE);
}
@Override
public List<RecommendedItem> recommend(final long userId, final int recommendNum) throws TasteException {
return this.recommender.recommend(userId, recommendNum);
}
/**
* @param userId
* @param recommendNum
* @param includeKnownItems --是否在推荐中包含用户已经获取过的内容
* @return
* @throws TasteException
*/
@Override
public List<RecommendedItem> recommend(long userId, int recommendNum, boolean includeKnownItems) throws TasteException {
return this.recommender.recommend(userId, recommendNum, includeKnownItems);
}
/**
* @param userId
* @param recommendNum
* @param idRescorer --在确定最终推荐列表之前应用的评分函数
* @return
* @throws TasteException
*/
@Override
public List<RecommendedItem> recommend(long userId, int recommendNum, IDRescorer idRescorer) throws TasteException {
return this.recommender.recommend(userId, recommendNum, idRescorer, false);
}
@Override
public List<RecommendedItem> recommend(long userId, int recommendNum, IDRescorer idRescorer, boolean includeKnownItems) throws TasteException {
return this.recommender.recommend(userId, recommendNum, idRescorer, includeKnownItems);
}
/**
* 估计偏好,如果用户没有表示对该项目的偏好,或者用户对该项目的实际偏好。如果无法估计首选项,则返回Double.NaN
* @param userId
* @param itemId --要估计偏好的项目ID
* @return
* @throws TasteException
*/
@Override
public float estimatePreference(long userId, long itemId) throws TasteException {
return this.recommender.estimatePreference(userId, itemId);
}
@Override
public void setPreference(long userID, long itemID, float value) throws TasteException {
this.recommender.setPreference(userID, itemID, value);
}
@Override
public void removePreference(long userID, long itemID) throws TasteException {
this.recommender.removePreference(userID, itemID);
}
@Override
public DataModel getDataModel() {
return this.recommender.getDataModel();
}
@Override
public void refresh(Collection<Refreshable> alreadyRefreshed) {
this.recommender.refresh(alreadyRefreshed);
}
}
最后,其实上述封装代码知识为了符合MVC的开发思想,从代码结构上更加清晰明了。好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊