一个Prefernence对象表示一个用户对一个物品的偏好,是(用户ID,物品ID,偏好值)的抽象。最有可能实现的是:
new GenericPreference(123, 456, 3.0f) //分别代表(用户ID,物品ID,偏好值)
如果要实现一组Prefernence,不能使用Collection or Prefernence[],因为这时候十分的占用内存。针对这种情况Mahout提供了PreferenceArray接口,表示一个偏好的聚合。这里可以举个例子:
GenericUserPrefernenceArray表示的是与某个用户关联的所有偏好。其内部包含一个单一用户ID,一个物品ID数组,以及一个偏好值数组。
PreferenceArray user1Prefs = new GenericUserPreferenceArray(2);
user1Prefs.setUserID(0, 1L);//设置用户ID
user1Prefs.setItemID(0, 101L);
user1Prefs.setValue(0, 2.0f);
user1Prefs.setItemID(1, 102L);
user1Prefs.setValue(1, 3.0f);
Preference pref = user1Prefs.get(1);//提取物品102的偏好值
在Mahout里面有许多Map和Set的数据结构,但是这个和Java里面的集合有些不同。
它简单地将偏好作为输入,采用FastByIDMap的形式,将用户ID映射到这些用户的数据所在的PreferenceArray上。
FastByIDMap<PreferenceArray> preferences = new FastByIDMap<PreferenceArray>();
PreferenceArray prefsForUser1 = new GenericUserPreferenceArray(10);
prefsForUser1.setUserID(0, 1L);
prefsForUser1.setItemID(0, 101L);//增加偏好
prefsForUser1.setValue(0, 3.0f);
prefsForUser1.setItemID(1, 102L);
prefsForUser1.setValue(1, 4.5f);
preferences.put(1L, prefsForUser1);//在输入中附上用户1的偏好
DataModel model = new GenericDataModel(preferences);
有时候我们会遇到没有评分的时候,只知道用户和物品是否关联,这时候称之为布尔型偏好。关于布尔型偏好的时候,书中举了个例子需要使用布尔型偏好的情况。一个人只对古典音乐感兴趣,对古典音乐家A给了很低的评分,给了古典音乐家B很高的评分,这个时候通过评分不能说明他对古典音乐是否感兴趣,但是如果这个时候转换成布尔型就可以了。
当使用无偏好值内存会得到大大节省,这个时候使用GenericBooleanPrefDataModel,这个将关联存为FastIDSet,没有偏好值。
给段代码看看:
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.eval.IRStatistics;
import org.apache.mahout.cf.taste.eval.RecommenderBuilder;
import org.apache.mahout.cf.taste.eval.RecommenderIRStatsEvaluator;
import org.apache.mahout.cf.taste.impl.eval.GenericRecommenderIRStatsEvaluator;
import org.apache.mahout.cf.taste.impl.model.GenericBooleanPrefDataModel;
import org.apache.mahout.cf.taste.impl.model.file.*;
import org.apache.mahout.cf.taste.impl.neighborhood.*;
import org.apache.mahout.cf.taste.impl.recommender.*;
import org.apache.mahout.cf.taste.impl.similarity.*;
import org.apache.mahout.cf.taste.model.*;
import org.apache.mahout.cf.taste.neighborhood.*;
import org.apache.mahout.cf.taste.recommender.*;
import org.apache.mahout.cf.taste.similarity.*;
import org.apache.mahout.common.RandomUtils;
import java.io.*;
class RecommenderIntro {
public static void main(String[] args) throws Exception {
RandomUtils.useTestSeed();
DataModel model = new GenericBooleanPrefDataModel(GenericBooleanPrefDataModel.toDataMap(new FileDataModel(new File("/Users/ericxk/Downloads/ml-100k/ua.base"))));
RecommenderIRStatsEvaluator evaluator = new GenericRecommenderIRStatsEvaluator();
RecommenderBuilder recommenderBuilder = new RecommenderBuilder() {
public Recommender buildRecommender(DataModel model)throws TasteException {
UserSimilarity similarity = new PearsonCorrelationSimilarity(model);
UserNeighborhood neighborhood =new NearestNUserNeighborhood(2, similarity, model);
return new GenericUserBasedRecommender(model, neighborhood, similarity);
}
};
IRStatistics stats = evaluator.evaluate(recommenderBuilder, null, model, null, 2, GenericRecommenderIRStatsEvaluator.CHOOSE_THRESHOLD, 1.0);
System.out.println(stats.getPrecision());
System.out.println(stats.getRecall());
}
}
最后文中讨论了用LogLikelihoodSimilarity代替PearsonCorrelationSimilarity,以及如果有缺失值的情况,关于这些后面章节会深入讨论。