Mahout中的一些相似度算法实现解读

Mahout中实现的推荐算法是协同过滤,而无论是UserCF还是ItemCF都依赖于user相似度或item相似度。本文是对mahout中的一些相似度算法的解读。

Mahout相似度相关类关系如下:

有点乱(^.^)

    从上图可看出,Mahout主要针对用户相似度和物品相似度的计算,并且除了HybridSimilarity之外全都能够用于计算user和item两者的相似度,只有HybridSimilarity只能计算item相似度。接来下分三部分进行分析:继承AbstractSimilarity的,没有集成AbstractSimilarity但是也可以用于user、item相似度计算的,只继承AbstractItemSimilarity的。

继承AbstractSimilarity的实现类

    以下这些类用于无偏好值的用户行为数据。
    在介绍EuclideanDistanceSimilarity、PearsonCorrelationSimilarity、UncenteredCosineSimilarity之前,让我们先了解一下AbstractSimilarity。其实AbstractSimilarity才是这一部分的核心,三个重要方法:userSimilarity()、itemSimilarity()、computeResult(),其中computeResult()是抽象方法,是供给子类去实现的,userSimilarity()、itemSimilarity()中会在计算好相应变量之后调用子类实现的computeResult(),得到的结果在经过处理之后就是相似度。
    在userSimilarity()中,会先计算
user1对物品X偏好值的和sumX以及平方和sumX2、user2对物品Y的偏好值的和sumY以及平方和sumY2、user1与user2的物品的偏好值的乘积sumXY、user1(item1)与user2(item2)的偏好值的平方差sumXYdiff2。代码如下:

sumXY += x * y;
    sumX += x;
    sumX2 += x * x;
    sumY += y;
    sumY2 += y * y;
    double diff = x - y;
    sumXYdiff2 += diff * diff;
    count++;

    其中如果一个user没有对某个item的偏好而另一个user有对这个item的偏好,那么会使用PreferenceInferrer实现类对进行推测,代码如下: 

// Only one user expressed a preference, but infer the other one's preference and tally
    // as if the other user expressed that preference
    if (compare < 0) {
    // X has a value; infer Y's
        x = hasPrefTransform
            ? prefTransform.getTransformedValue(xPrefs.get(xPrefIndex))
            : xPrefs.getValue(xPrefIndex);
        y = inferrer.inferPreference(userID2, xIndex);
     } else {
      // compare > 0
        // Y has a value; infer X's
        x = inferrer.inferPreference(userID1, yIndex);
        y = hasPrefTransform
            ? prefTransform.getTransformedValue(yPrefs.get(yPrefIndex))
            : yPrefs.getValue(yPrefIndex);
     }

    然后会调用computeResult()方法,代码如下: 

// "Center" the data. If my math is correct, this'll do it.
    double result;
    if (centerData) {
      double meanX = sumX / count;
      double meanY = sumY / count;
      // double centeredSumXY = sumXY - meanY * sumX - meanX * sumY + n * meanX * meanY;
      double centeredSumXY = sumXY - meanY * sumX;
      // double centeredSumX2 = sumX2 - 2.0 * meanX * sumX + n * meanX * meanX;
      double centeredSumX2 = sumX2 - meanX * sumX;
      // double centeredSumY2 = sumY2 - 2.0 * meanY * sumY + n * meanY * meanY;
      double centeredSumY2 = sumY2 - meanY * sumY;
      result = computeResult(count, centeredSumXY, centeredSumX2, centeredSumY2, sumXYdiff2);
    } else {
      result = computeResult(count, sumXY, sumX2, sumY2, sumXYdiff2);
    }

    最后,在经过SimilarityTransform和normalizeWeightResult()两步处理,result就是求得的user1与user2的相似度数值。代码如下: 

if (similarityTransform != null) {
      result = similarityTransform.transformSimilarity(itemID1, itemID2, result);
    }

    if (!Double.isNaN(result)) {
      result = normalizeWeightResult(result, count, cachedNumUsers);
    }

    1.PearsonCorrelationSimilarity 
    基于皮尔森相关性的相似度计算:sumXY / sqrt(sumX2 * sumY2),代码如下:

@Override
double computeResult(int n, double sumXY, double sumX2, double sumY2, double sumXYdiff2) {
    if (n == 0) {
      return Double.NaN;
    }
    // Note that sum of X and sum of Y don't appear here since they are assumed to be 0;
    // the data is assumed to be centered.
    double denominator = Math.sqrt(sumX2) * Math.sqrt(sumY2);
    if (denominator == 0.0) {
      // One or both parties has -all- the same ratings;
      // can't really say much similarity under this measure
      return Double.NaN;
    }
    return sumXY / denominator;
}

    2.EuclideanDistanceSimilarity 
    基于欧几里德距离的相似度计算:1 / (1 + distance),代码如下:

@Override
double computeResult(int n, double sumXY, double sumX2, double sumY2, double sumXYdiff2) {
    return 1.0 / (1.0 + Math.sqrt(sumXYdiff2) / Math.sqrt(n));
}

    3.UncenteredCosineSimilarity 
    基于余弦的相似度计算,代码如下:

@Override
double computeResult(int n, double sumXY, double sumX2, double sumY2, double sumXYdiff2) {
    if (n == 0) {
      return Double.NaN;
    }
    double denominator = Math.sqrt(sumX2) * Math.sqrt(sumY2);
    if (denominator == 0.0) {
      // One or both parties has -all- the same ratings;
      // can't really say much similarity under this measure
      return Double.NaN;
    }
    return sumXY / denominator;
}

继承AbstractItemSimilarity并实现AbstractItemSimilarity的类

    以下这些类用于无偏好值的用户行为数据。
    1.TanimotoCoefficientSimilarity
    基于谷本系数的相似度:userID1的偏好物品与userID2的偏好物品的交集size/并集size(item与其类似),代码如下:

public double userSimilarity(long userID1, long userID2) throws TasteException {

    DataModel dataModel = getDataModel();
    FastIDSet xPrefs = dataModel.getItemIDsFromUser(userID1);
    FastIDSet yPrefs = dataModel.getItemIDsFromUser(userID2);

    int xPrefsSize = xPrefs.size();
    int yPrefsSize = yPrefs.size();
    if (xPrefsSize == 0 && yPrefsSize == 0) {
      return Double.NaN;
    }
    if (xPrefsSize == 0 || yPrefsSize == 0) {
      return 0.0;
    }

    //计算交集的size
    int intersectionSize =
        xPrefsSize < yPrefsSize ? yPrefs.intersectionSize(xPrefs) : xPrefs.intersectionSize(yPrefs);
    if (intersectionSize == 0) {
      return Double.NaN;
    }
    //计算并集size
    int unionSize = xPrefsSize + yPrefsSize - intersectionSize;

    return (double) intersectionSize / (double) unionSize;
  }

    2.LogLikelihoodSimilarity 
    基于对数似然的相似度:基于谷本系数的相似度的升级版,代码如下: 

public double userSimilarity(long userID1, long userID2) throws TasteException {
    DataModel dataModel = getDataModel();
    FastIDSet prefs1 = dataModel.getItemIDsFromUser(userID1);
    FastIDSet prefs2 = dataModel.getItemIDsFromUser(userID2);

    long prefs1Size = prefs1.size();
    long prefs2Size = prefs2.size();
    //计算交集size
    long intersectionSize =
        prefs1Size < prefs2Size ? prefs2.intersectionSize(prefs1) : prefs1.intersectionSize(prefs2);
    if (intersectionSize == 0) {
      return Double.NaN;
    }
    long numItems = dataModel.getNumItems();
    double logLikelihood =
        LogLikelihood.logLikelihoodRatio(intersectionSize,
                                         prefs2Size - intersectionSize,
                                         prefs1Size - intersectionSize,
                                         numItems - prefs1Size - prefs2Size + intersectionSize);
    return 1.0 - 1.0 / (1.0 + logLikelihood);
  }

    3.CityBlockSimilarity 
    基于街区距离的相似度,代码如下: 

public double userSimilarity(long userID1, long userID2) throws TasteException {
    DataModel dataModel = getDataModel();
    FastIDSet prefs1 = dataModel.getItemIDsFromUser(userID1);
    FastIDSet prefs2 = dataModel.getItemIDsFromUser(userID2);
    int prefs1Size = prefs1.size();
    int prefs2Size = prefs2.size();
    int intersectionSize = prefs1Size < prefs2Size ? prefs2.intersectionSize(prefs1) : prefs1.intersectionSize(prefs2);
    return doSimilarity(prefs1Size, prefs2Size, intersectionSize);
  }
//Calculate City Block Distance from total non-zero values and intersections and map to a similarity value.
private static double doSimilarity(int pref1, int pref2, int intersection) {
    int distance = pref1 + pref2 - 2 * intersection;
    return 1.0 / (1.0 + distance);
}

只继承AbstractItemSimilarity的实现类

    1.TrackItemSimilarity
    代码如下:

public double itemSimilarity(long itemID1, long itemID2) {
    if (itemID1 == itemID2) {
      return 1.0;
    }
    TrackData data1 = trackData.get(itemID1);
    TrackData data2 = trackData.get(itemID2);
    if (data1 == null || data2 == null) {
      return 0.0;
    }

    // Arbitrarily decide that same album means "very similar"
    if (data1.getAlbumID() != TrackData.NO_VALUE_ID && data1.getAlbumID() == data2.getAlbumID()) {
      return 0.9;
    }
    // ... and same artist means "fairly similar"
    if (data1.getArtistID() != TrackData.NO_VALUE_ID && data1.getArtistID() == data2.getArtistID()) {
      return 0.7;
    }

    // Tanimoto coefficient similarity based on genre, but maximum value of 0.25
    FastIDSet genres1 = data1.getGenreIDs();
    FastIDSet genres2 = data2.getGenreIDs();
    if (genres1 == null || genres2 == null) {
      return 0.0;
    }
    int intersectionSize = genres1.intersectionSize(genres2);
    if (intersectionSize == 0) {
      return 0.0;
    }
    int unionSize = genres1.size() + genres2.size() - intersectionSize;
    return (double) intersectionSize / (4.0 * unionSize);
}

    2.HybridSimilarity 
    基于混合的相似度计算:LogLikelihoodSimilarity*TrackItemSimilarity。代码如下: 

HybridSimilarity(DataModel dataModel, File dataFileDirectory) throws IOException {
    super(dataModel);
    cfSimilarity = new LogLikelihoodSimilarity(dataModel);
    contentSimilarity = new TrackItemSimilarity(dataFileDirectory);
  }

public double itemSimilarity(long itemID1, long itemID2) throws TasteException {
    return contentSimilarity.itemSimilarity(itemID1, itemID2) * cfSimilarity.itemSimilarity(itemID1, itemID2);
}
时间: 2024-11-04 16:29:59

Mahout中的一些相似度算法实现解读的相关文章

[推荐系统]Mahout中相似度计算方法介绍

Mahout中相似度计算方法介绍      在现实中广泛使用的推荐系统一般都是基于协同过滤算法的,这类算法通常都需要计算用户与用户或者项目与项目之间的相似度,对于数据量以及数据类型不同的数据源,需要不同的相似度计算方法来提高推荐性能,在mahout提供了大量用于计算相似度的组件,这些组件分别实现了不同的相似度计算方法.下图用于实现相似度计算的组件之间的关系: 图1.项目相似度计算组件 图2.用户相似度计算组件 下面就几个重点相似度计算方法做介绍: 皮尔森相关度 类名:PearsonCorrela

图像相似度算法的一点粗糙应用——GUI测试

因为一些私人的事情,本来早已经应该完成的一篇文章一直到今天才可以草草了结.在前面的两篇文 章<图像相似度算法的C#实现及测评><对"画条线"(Draw a line)的单元测试几点想法和实践 >中 ,先后介绍了一个简单的会读直方图算法和一些关于GUI画图的测试想法.有必要说明的是,在<对"画 条线"(Draw a line)的单元测试几点想法和实践>中提到的几种方法,最实用的是Mock法并不是今天 的主题. 这篇文章中继续前面的思

从相似度算法谈起 - Effective similarity search in PostgreSQL

标签 PostgreSQL , 数组 , 相似度 , 文本分析 , 图像分析 , 字符串分析 , 婚姻介绍 , 精确配对 背景 相似度分析是一个非常普遍的需求,例如根据用户提供的线索,从一堆文本数据.图片数据.视频数据中筛选一段与用户的描述相近的. 我之前写过一系列的文章来介绍,文本.图片相似度搜索的技术和使用场景. <PostgreSQL 在视频.图片去重,图像搜索业务中的应用> <弱水三千,只取一瓢,当图像搜索遇见PostgreSQL(Haar wavelet)> <聊一

相似度算法(http://blog.sina.com.cn/s/blog_62b83291010127bf.html)

在数据分析和数据挖掘的过程中,我们经常需要知道个体间差异的大小,进而评价个体的相似性和类别.最常见的是数据分析中的相关分析,数据挖掘中的分 类和聚类算法,如K最近邻(KNN)和K均值(K-Means).当然衡量个体差异的方法有很多,最近查阅了相关的资料,这里整理罗列下. 为了方便下面的解释和举例,先设定我们要比较X个体和Y个体间的差异,它们都包含了N个维的特征,即X=(x1, x2, x3, - xn),Y=(y1, y2, y3, - yn).下面来看看主要可以用哪些方法来衡量两者的差异,主要

PHP中计算字符串相似度的函数代码_php技巧

similar_text - 计算两个字符串的相似度 int similar_text ( string $first , string $second [, float &$percent ] ) $first 必需.规定要比较的第一个字符串. $second 必需.规定要比较的第二个字符串. $percent 可选.规定供存储百分比相似度的变量名. 两个字符串的相似程度计算依据 Oliver [1993] 的描述进行.注意该实现没有使用 Oliver 虚拟码中的堆栈,但是却进行了递归调用,这

通过余弦相似度算法计算用户相似度时具体怎么做

问题描述 通过余弦相似度算法计算用户相似度时具体怎么做 按用户购买的物品,具体怎么样计算...................... 解决方案 http://blog.csdn.net/cscmaker/article/details/7990600

Python中使用hashlib模块处理算法的教程

  这篇文章主要介绍了Python中使用hashlib模块处理算法的教程,代码基于Python2.x版本,需要的朋友可以参考下 Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等. 什么是摘要算法呢?摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示). 举个例子,你写了一篇文章,内容是一个字符串'how to use python hashlib - by Michael',并附上这篇文章的摘要是'2d7

PS中色相饱合度/可选颜色/色彩平衡/曲线的区别和运用方法

  PS中色相饱合度/可选颜色/色彩平衡/曲线的区别和运用方法详解 整体思路: 1.使用颜色混合模式营造照片基调. 2.使用色彩平衡对不同曝光区域进行调整,营造色偏. 3.使用可选颜色加强灯光的表现力. 4.用海绵工具或者HSL调节加强灯光的饱和度. 5.锐化. 6.暗角. 按颜色分: 可选颜色工具.色相/饱和度工具. 这两个工具是以颜色本身作为分类依据进行调整的. 可选颜色一般用于微调,制造色偏. 色相/饱和度工具一般用于大幅度调整,改变色彩性状. 按亮度分: 色彩平衡工具. 色彩平衡工具是以

javascript实现图片相似度算法

 这篇文章主要介绍了javascript实现图片相似度算法,大家参考使用吧 代码如下: function getHistogram(imageData) {     var arr = [];     for (var i = 0; i < 64; i++) {         arr[i] = 0;     }     var data = imageData.data;     var pow4 = Math.pow(4, 2);     for (var i = 0, len = data