散列函数python中的family生成器

时间:2010-02-12 22:37:45

标签: python hash generator

我正在寻找一个哈希函数族生成器,它可以在给定一组参数的情况下生成一系列哈希函数。到目前为止我还没有找到任何这样的发电机。 有没有办法用hashlib包来做到这一点?

例如,我想做类似的事情:

h1 = hash_function(1)
h2 = hash_function(2)
...

h1以及h2将是不同的哈希函数。

对于那些可能了解它的人,我正在尝试在非常大的数据集上实现最小哈希算法。

基本上,对于给定的文档,我有一组非常大的特征(1亿到10亿),我需要为这组特征创建1000到10000个不同的随机排列。

我不想明确构建随机排列,所以我想在下面使用这个技术:

  1. 生成哈希函数h并考虑两个索引rs
  2. 如果r,则{li> s出现在排列h(r) < h(s)之前,并为100到1000个不同的哈希函数执行此操作。

    我可能错过了任何已知的图书馆吗?或者你可能知道的使用python生成哈希函数族的任何标准方法?

5 个答案:

答案 0 :(得分:6)

我只是做了类似的事情(如果你不需要线程安全 - 如果你需要线程安全并不难改变 - 并假设一个32位的Python版本):

import random

_memomask = {}

def hash_function(n):
  mask = _memomask.get(n)
  if mask is None:
    random.seed(n)
    mask = _memomask[n] = random.getrandbits(32)
  def myhash(x):
    return hash(x) ^ mask
  return myhash

答案 1 :(得分:1)

如上所述,您可以对minhash使用通用哈希。 例如:

import random



def minhash():
    d1 = set(random.randint(0, 2000) for _ in range(1000))
    d2 = set(random.randint(0, 2000) for _ in range(1000))
    jacc_sim = len(d1.intersection(d2)) / len(d1.union(d2))
    print("jaccard similarity: {}".format(jacc_sim))

    N_HASHES = 200
    hash_funcs = []
    for i in range(N_HASHES):
        hash_funcs.append(universal_hashing())

    m1 = [min([h(e) for e in d1]) for h in hash_funcs]
    m2 = [min([h(e) for e in d2]) for h in hash_funcs]
    minhash_sim = sum(int(m1[i] == m2[i]) for i in range(N_HASHES)) / N_HASHES
    print("min-hash similarity: {}".format(minhash_sim))



def universal_hashing():
    def rand_prime():
        while True:
            p = random.randrange(2 ** 32, 2 ** 34, 2)
            if all(p % n != 0 for n in range(3, int((p ** 0.5) + 1), 2)):
                return p
    m = 2 ** 32 - 1
    p = rand_prime()
    a = random.randint(0, p)
    if a % 2 == 0:
        a += 1
    b = random.randint(0, p)
    def h(x):
        return ((a * x + b) % p) % m
    return h

Reference

答案 2 :(得分:0)

您应该考虑使用通用哈希。我的答案和代码可以在这里找到:https://stackoverflow.com/a/25104050/207661

答案 3 :(得分:0)

@alex的回答虽然简洁明了,但是它生成的哈希函数并没有“彼此非常不同”的意思。

让我们看一下10000个哈希中的10000个样本之间的Pearson相关性,结果将结果放入100个bin中

$mgClient = Mailgun::create('PRIVATE_API_KEY', 'https://'.API_HOSTNAME);

即p_value的中位数是%%time # 1min 14s n=10000 hashes = [hash_function(i) for i in range(n)] median_pvalue(hashes, n=n) # 1.1614081043690444e-06 ,这远非随机。这是一个真正随机的示例:

1e-06

使用Carter和Wegman方法,您可以获得:

%%time # 4min 15s
hashes = [lambda _ : random.randint(0,100) for _ in range(n)]
median_pvalue(hashes, n=n)
# 0.4979718236429698

要复制的代码:

%%time # 1min 43s
hashes = HashFamily(100).draw_hashes(n)
median_pvalue(hashes, n=n)
# 0.841929288037321

请注意,我的实现是在Carter和Wegman的基础上非常幼稚的(例如生成质数)。它可以做得更短,更快。

答案 4 :(得分:0)

universal hash family 是一组大小为 H 的散列函数 m,这样当散列函数1/m 从集合 h 中随机抽取。

universal hash family

基于维基百科的表述,使用可以使用以下代码:

H

示例用法:

我们可以创建一个由 20 个散列函数组成的散列族,每个散列函数将输入映射到 100 个桶。

import random

def is_prime(n):
    if n==2 or n==3: return True
    if n%2==0 or n<2: return False
    for i in range(3, int(n**0.5)+1, 2):
        if n%i==0:
            return False    
    return True

# universal hash functions
class UniversalHashFamily:
    def __init__(self, number_of_hash_functions, number_of_buckets, min_value_for_prime_number=2, bucket_value_offset=0):
        self.number_of_buckets = number_of_buckets
        self.bucket_value_offset = bucket_value_offset
        
        primes = []
        number_to_check = min_value_for_prime_number
        while len(primes) < number_of_hash_functions:
            if is_prime(number_to_check):
                primes.append(number_to_check)
            number_to_check += random.randint(1, 1000)

        self.hash_function_attrs = []
        for i in range(number_of_hash_functions):
            p = primes[i]
            a = random.randint(1, p)
            b = random.randint(0, p)
            self.hash_function_attrs.append((a, b, p))
    
    def __call__(self, function_index, input_integer):
        a, b, p = self.hash_function_attrs[function_index]
        return (((a*input_integer + b)%p)%self.number_of_buckets) + self.bucket_value_offset

并获取散列值,例如:

hash_family = UniversalHashFamily(20, 100)

如果您对 string 输入的通用哈希系列感兴趣,可以使用以下代码。但请注意,此代码可能不是字符串散列的优化方案。

input_integer = 1234567890 # sample input

hash_family(0, input_integer) # the output of the first hash function, i.e. h0(input_integer)
hash_family(1, input_integer) # the output of the second hash function, i.e. h1(input_integer)
# ...
hash_family(19, input_integer) # the output of the last hash function, i.e. h19(input_integer)