Mahout之minhash

Minhash原理

先介绍一个概念-局部敏感哈希:

LSH:local sensitive hash,局部敏感哈希

LSH是一种概率方法,采用过滤一验证的框架(Filter一and一Refine framework)。在过滤阶段,LSH利用哈希技术把非相似、不可能成为结果的数据对象过滤掉,过滤之后的数据对象作为候选集(CandidateSet),使得相似的数据对象以很高的概率留候选集合中,进而在候选集合上进行实际的距离或者相似性度量计算。由于在过滤阶段非相似的数据对象大部分被过滤掉,候选集合的大小必定会远小于原始数据集,因而极大地缩短了查询计算时间,提高了效率。

Minhash就是LSH的一种,主要作用是降维,Mahout用Minhash进行聚类

 

再介绍第二个概念-Jaccard index

Jaccard index是用来计算距离的一种标准。
假如有集合A、B,那么J(A,B)=(A ∩B)/ (A∪B)
即A,B的Jaccard系数等于A,B中共同拥有的元素数与A,B总共拥有的元素数之比。
 

那么如何用minhash计算jaccard index,以便求得2个集合的相似度呢?

方法如下:

1.多个hash函数
选择一定数量的hash函数,比如K个。然后用这K个hash函数分别对集合A、B求哈希值,对每个集合都得到K个最小值。比如Min(A)k={a1,a2,...,ak},Min(B)k={b1,b2,...,bk}。
那么,集合A、B的相似度为|Min(A)k ∩ Min(B)k| / |Min(A)k ∪ Min(B)k|,即Min(A)k和Min(B)k中相同元素个数与总的元素个数的比例。
2,.单个hash函数
第一种方法有一个很明显的缺陷,那就是计算复杂度高。单个hash函数可以解决这个问题:只用一个hash函数,求集合S中具有最小哈希值的K个元素。这样一来,
只需要对每个集合求一次哈希,然后取最小的K个元素。计算两个集合A、B的相似度,就是集合A中最小的K个元素与集合B中最小的K个元素的交集个数与并集个数的比例。

 

Mahout MinHash代码阅读

1.MinHashDriver类,包含一个map和一个reduce

//解析参数                                                                                                                                                          int minClusterSize = Integer.valueOf(getOption(MinhashOptionCreator.MIN_CLUSTER_SIZE));//每个类中的最小point个数,默认10
    int minVectorSize = Integer.valueOf(getOption(MinhashOptionCreator.MIN_VECTOR_SIZE));//最小向量大小,默认5
    String hashType = getOption(MinhashOptionCreator.HASH_TYPE);//Hash类型,可选: (linear, polynomial, murmur),默认murmur
    int numHashFunctions = Integer.valueOf(getOption(MinhashOptionCreator.NUM_HASH_FUNCTIONS));//Hash函数的个数,默认10
    int keyGroups = Integer.valueOf(getOption(MinhashOptionCreator.KEY_GROUPS));//key的组数,默认2
    int numReduceTasks = Integer.parseInt(getOption(MinhashOptionCreator.NUM_REDUCERS));//reduce个数,默认2
    boolean debugOutput = hasOption(MinhashOptionCreator.DEBUG_OUTPUT);//debug的输出路径

参数解析完了就可以跑mapred的内容了。


2.MinHashMapper类

首先对输入的Vector进行处理,如果Vector的size小于预先设置的minVectorSize则过滤这条数据;

if (featureVector.size() < minVectorSize) {
      return;
    }


然后初始化赋值到数组里,数组的大小就是hash函数的个数,默认赋值为Integer.MAX_VALUE;

for (int i = 0; i < numHashFunctions; i++) {
      minHashValues[i] = Integer.MAX_VALUE;
    }


再对这个向量计算hash值,注意注释的地方,始终采用hash出来的最小值放在数组中;

for (int i = 0; i < numHashFunctions; i++) {
      for (Vector.Element ele : featureVector) {
        int value = (int) ele.get();
        bytesToHash[0] = (byte) (value >> 24);
        bytesToHash[1] = (byte) (value >> 16);
        bytesToHash[2] = (byte) (value >> 8);
        bytesToHash[3] = (byte) value;
        int hashIndex = hashFunction[i].hash(bytesToHash);
        //if our new hash value is less than the old one, replace the old one
        if (minHashValues[i] > hashIndex) {
          minHashValues[i] = hashIndex;
        }
      }
    }


最后就是输出信息到reduce了,代码省略。注意的是keyGroups,在将向量每个hash值拼接起来作key的时候使用了它,是为了避免向量之间的冲突。

3.MinHashReducer类

主要就是将在一个key下的value放到list里,list的size<minClusterSize时候就过滤,并且用计数器统计了大小。这里的输出并不是最终结果,要输出最终还得自己写代码。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值