【问题标题】:Can you suggest a good minhash implementation?你能推荐一个好的minhash实现吗?
【发布时间】:2018-09-27 18:14:16
【问题描述】:

我正在尝试寻找可以用于我的工作的 minhash 开源实现。

我需要的功能非常简单,给定一个集合作为输入,实现应该返回它的 minhash。

最好使用 python 或 C 实现,以防我需要破解它来为我工作。

任何指针都会有很大帮助。

问候。

【问题讨论】:

    标签: python hash minhash


    【解决方案1】:

    您应该按顺序查看以下开源库。它们都在 Python 中,并展示了如何使用 LSH/MinHash 计算文档相似度:

    lsh
    LSHHDC : Locality-Sensitive Hashing based High Dimensional Clustering
    MinHash

    【讨论】:

      【解决方案2】:

      看看datasketch library。它支持序列化和合并。它是在纯python中实现的,没有外部依赖。 Go version 具有完全相同的功能。

      【讨论】:

      • 谢谢@ekzhu。 Datasketch 看起来是解决我遇到的哈希问题的最佳选择,我正在考虑 github.com/simonemainardi/LSHash
      • 呃,但只支持 Python 2.7。
      【解决方案3】:

      如果您有兴趣研究 minhash 算法,这里有一个非常简单的实现和一些讨论。

      要为集合生成 MinHash 签名,我们创建一个长度为 $N$ 的向量,其中所有值都设置为正无穷大。我们还创建了$N$ 函数,它们接受输入整数并置换该值。 $i^{th}$ 函数将单独负责更新向量中的 $i^{th}$ 值。给定这些值,我们可以通过将集合中的每个值传递给每个 $N$ 置换函数来计算集合的 minhash 签名。如果$i^{th}$ 置换函数的输出低于向量的$i^{th}$ 值,我们用置换函数的输出替换该值(这就是为什么哈希被称为“min em>-哈希”)。让我们在 Python 中实现它:

      from scipy.spatial.distance import cosine
      from random import randint
      import numpy as np
      
      # specify the length of each minhash vector
      N = 128
      max_val = (2**32)-1
      
      # create N tuples that will serve as permutation functions
      # these permutation values are used to hash all input sets
      perms = [ (randint(0,max_val), randint(0,max_val)) for i in range(N)]
      
      # initialize a sample minhash vector of length N
      # each record will be represented by its own vec
      vec = [float('inf') for i in range(N)]
      
      def minhash(s, prime=4294967311):
        '''
        Given a set `s`, pass each member of the set through all permutation
        functions, and set the `ith` position of `vec` to the `ith` permutation
        function's output if that output is smaller than `vec[i]`.
        '''
        # initialize a minhash of length N with positive infinity values
        vec = [float('inf') for i in range(N)]
      
        for val in s:
      
          # ensure s is composed of integers
          if not isinstance(val, int): val = hash(val)
      
          # loop over each "permutation function"
          for perm_idx, perm_vals in enumerate(perms):
            a, b = perm_vals
      
            # pass `val` through the `ith` permutation function
            output = (a * val + b) % prime
      
            # conditionally update the `ith` value of vec
            if vec[perm_idx] > output:
              vec[perm_idx] = output
      
        # the returned vector represents the minimum hash of the set s
        return vec
      

      这就是它的全部内容!为了演示我们如何使用这个实现,我们举一个简单的例子:

      import numpy as np
      
      # specify some input sets
      data1 = set(['minhash', 'is', 'a', 'probabilistic', 'data', 'structure', 'for',
              'estimating', 'the', 'similarity', 'between', 'datasets'])
      data2 = set(['minhash', 'is', 'a', 'probability', 'data', 'structure', 'for',
              'estimating', 'the', 'similarity', 'between', 'documents'])
      
      # get the minhash vectors for each input set
      vec1 = minhash(data1)
      vec2 = minhash(data2)
      
      # divide both vectors by their max values to scale values {0:1}
      vec1 = np.array(vec1) / max(vec1)
      vec2 = np.array(vec2) / max(vec2)
      
      # measure the similarity between the vectors using cosine similarity
      print( ' * similarity:', 1 - cosine(vec1, vec2) )
      

      这将返回 ~.9 作为这些向量之间相似度的度量。

      虽然我们只比较了上面的两个 minhash 向量,但我们可以使用“Locality Sensitive Hash”更简单地比较它们。为此,我们可以构建一个字典,将 $W$ MinHash 向量分量的每个序列映射到构造 MinHash 向量的集合的唯一标识符。例如,如果W = 4 和我们有一个集合S1,我们从中派生出一个MinHash 向量[111,512,736,927,817...],我们将添加S1 标识符到该向量中四个MinHash 值的每个序列:

      d[111-512-736-927].append('S1')
      d[512-736-927-817].append('S1')
      ...
      

      一旦我们对所有集合都这样做了,我们就可以检查字典中的每个键,如果该键有多个不同的集合 ID,我们有理由相信这些集合是相似的。实际上,一对集合 id 在字典中的单个值中出现的次数越多,这两个集合之间的相似性就越大。以这种方式处理我们的数据,我们可以将识别所有相似集合对的复杂度降低到大致线性时间!

      【讨论】:

        【解决方案4】:

        我建议你this library,特别是如果你需要坚持。在这里,您可以使用 redis 来存储/检索您的所有数据。

        您可以选择一个 redis 数据库,或者简单地使用内置的内存中 python 字典。

        使用 redis 的性能,至少如果 redis 服务器在您的本地计算机上运行,​​几乎与通过标准 python 字典实现的性能相同。

        你只需要指定一个配置字典比如

        config = {"redis": {"host": 'localhost', "port": '6739', "db": 0}}
        

        并将其作为参数传递给LSHash 类构造函数。

        【讨论】:

        • ekzhu写的datasketch现在也支持Redis后端了
        猜你喜欢
        • 2011-01-24
        • 1970-01-01
        • 1970-01-01
        • 2010-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-25
        • 2010-10-11
        相关资源
        最近更新 更多