mahout基于用户的推荐

《Mahout实战》第四章基于用户的推荐算法如下:

for每个其他用户w
    计算用户u和用户w的相似度s
    按相似度排序后,将位置靠前的用户作为邻域n
for(n中用户有偏好,而u中用户无偏好的)每个物品i
    for(n中用户对i有偏好的)每个其他用户v
    计算用户u和用户v的相似度n
    按权重s将v和i的偏好并入平均值

1 简单推荐引擎的评估
下面代码来自《Mahout实战》,数据来源于http://www.grouplens.org/node/73

import java.io.File;
import java.io.IOException;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.eval.RecommenderBuilder;
import org.apache.mahout.cf.taste.eval.RecommenderEvaluator;
import org.apache.mahout.cf.taste.impl.eval.AverageAbsoluteDifferenceRecommenderEvaluator;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.apache.mahout.cf.taste.similarity.precompute.example.GroupLensDataModel;

public class Demo43 {

    public static void main(String[] args) throws IOException, TasteException {
        DataModel model = new GroupLensDataModel(new File("F:/mawork/datas/ml-10M100K/ratings.dat"));
        RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator();
        RecommenderBuilder recommenderBuilder = new RecommenderBuilder() {
            @Override
            public Recommender buildRecommender(DataModel dataModel)
                    throws TasteException {
                UserSimilarity similarity = new PearsonCorrelationSimilarity(dataModel);
                UserNeighborhood neighborhood = new NearestNUserNeighborhood(100, similarity, dataModel);
                return new GenericUserBasedRecommender(dataModel, neighborhood, similarity);
            }
        };
        // 0.95表示使用95%的数据来构建评估模型,然后使用余下的5%做测试
        double score = evaluator.evaluate(recommenderBuilder, null, model, 0.95, 0.05);
        System.out.println(score);
    }
}

按照《Mahout实战》中JVM调优章节
调整最大堆空间为768m,内存的使用比没有配置的参数要好很多。
1
继续配置-Xmx768m -XX:+UseParallelOldGC,在我的机器上运行,并没有书上讲的时间降低
再次配置-server -Xmx768m -XX:+UseParallelOldGC,这次的配置比之前就好多了。JVM有两种运行模式,client模式和server模式,client模式特点是启动快、占用内存少、占用资源少,而server模式适合长时间运行,资源密模式,我们的推荐程序使用-server更合适。
不过按照《Java性能优化权威指南》中64位HotSpot虚拟机中没有提供Client模式,所以-server没有多大用了。
按照《Java性能优化权威指南》中给出的JVM指导原则,-Xmx2048m -d64 -XX:+UseCompressedOops -XX:+UseParallelOldGC,这里注意-XX:+UseCompressedOopsJava6之后HotSpot VM根据最大java堆情况自动启用。CPU使用率、GC明显下降
2
-XX:+UseParallelOldGC将同时启用多线程的新生代垃圾收集器和多线程的老年代垃圾收集器,而-XX:+UseParallelGC仅启用多线程的新生代垃圾收集器,使用-XX:+UseParallelOldGC将自动启用-XX:+UseParallelGC
1.1 固定大小的邻域
这里使用new NearestNUserNeighborhood(100, similarity, dataModel);,邻域大小设置为100,邻域值的大小需要在真实数据上做实验调优
1.2 基于阈值的邻域
这里将new NearestNUserNeighborhood(100, similarity, dataModel);调整为
UserNeighborhood neighborhood = new ThresholdUserNeighborhood(0.7, similarity, dataModel);
evaluator的得分越低越好,计算估计和实际偏好之间的平均差,值越低意味着估计值与实际偏好值的差别越小,评分0.0意味着完美的估计。ThresholdUserNeighborhood取的是百分比
2 相似度量
邻域只是通过固定大小或者阈值找到临近的用户,但怎么衡量这些用户的相似度是很重要的参数
2.1 皮尔逊相关系数
该系统度量两个变量的线性关系,存在的问题
1、没有考虑两个用户同时给出偏好值的物品数目。也就是说A、B用户对相同物品评价数量为100,而A、C对相同物品评价为60,但是皮尔逊只计算相关性,并不在乎相同物品数量的多少来判断用户之间的共性。
2、在小或稀疏的数据集,无法计算相关性,因为用户的物品集很少重叠
3、只要任何一序列中出现偏好值相同的情况,相关系统都是未定义的。因为皮尔逊相关系数是两个序列协方差与二者方差乘积的比值,序列相同,方差为0。
书上说解决的办法是引入权重,
UserSimilarity similarity = new PearsonCorrelationSimilarity(dataModel, Weighting.WEIGHTED);
可以使权重的标准是什么呢?在org.apache.mahout.cf.taste.impl.similarity.userSimilarity中可以看到他是对皮尔逊系统进行加权

if (!Double.isNaN(result)) {
      result = normalizeWeightResult(result, count, cachedNumItems);
    }
  final double normalizeWeightResult(double result, int count, int num) {
    double normalizedResult = result;
    if (weighted) {
      double scaleFactor = 1.0 - (double) count / (double) (num + 1);
      if (normalizedResult < 0.0) {
        normalizedResult = -1.0 + scaleFactor * (1.0 + normalizedResult);
      } else {
        normalizedResult = 1.0 - scaleFactor * (1.0 - normalizedResult);
      }
    }
    // Make sure the result is not accidentally a little outside [-1.0, 1.0] due to rounding:
    if (normalizedResult < -1.0) {
      normalizedResult = -1.0;
    } else if (normalizedResult > 1.0) {
      normalizedResult = 1.0;
    }
    return normalizedResult;
  }

跟踪调试,加了权重并没有解决只要任何一序列中出现偏好值相同的情况,相关系统都是未定义的这个问题,他只考虑了在物品数量上进行加权修正。
3
2.2 欧氏距离
这里将new NearestNUserNeighborhood(100, similarity, dataModel);调整为
UserSimilarity similarity = new EuclideanDistanceSimilarity(dataModel);
1
下图做了假设,例如用户3并没有对物品102进行评价,则差值为0.相似度最终取1/(1+d)
2
2.3 余弦相似度
mahout将余弦相似度与皮尔逊的度量标准定义为一样的,理由是Mahout将输入中心化
什么是数据中心化呢,参考数据什么时候需要做中心化和标准化处理?,中心化的理由是得到均值为0,标准差为1的服从标准正态分布的数据。
2.4 斯皮尔曼相关系数
这里将new NearestNUserNeighborhood(100, similarity, dataModel);调整为
UserSimilarity similarity = new SpearmanCorrelationSimilarity(dataModel);
该系数是根据偏好值的相对排名来计算,而不是原始的偏好值,他的计算很慢,书上说学术价值大于实用价值。
2.5 谷本系数
忽略偏好值,偏好物品集合的交集大小与并集大小的比值, 这个计算也比较慢
这里将new NearestNUserNeighborhood(100, similarity, dataModel);调整为
UserSimilarity similarity = new TanimotoCoefficientSimilarity(dataModel);
2.6 对数似然比
该系数是一个逆向思维,考虑判断两个用户口味不相似的不可能性有多大,不可能性越大,相似度也就越高
1
我一开始很困惑,这上面的相似值是怎么计算出来的,可以参考对数似然比相似度,计算过程貌似挺复杂的,理解应用场景就好。

猜你喜欢

转载自blog.csdn.net/warrah/article/details/80063509