我正在寻找一个哈希函数族生成器,它可以在给定一组参数的情况下生成一系列哈希函数。到目前为止我还没有找到任何这样的发电机。
有没有办法用hashlib
包来做到这一点?
例如,我想做类似的事情:
h1 = hash_function(1)
h2 = hash_function(2)
...
和h1
以及h2
将是不同的哈希函数。
对于那些可能了解它的人,我正在尝试在非常大的数据集上实现最小哈希算法。
基本上,对于给定的文档,我有一组非常大的特征(1亿到10亿),我需要为这组特征创建1000到10000个不同的随机排列。
我不想明确构建随机排列,所以我想在下面使用这个技术:
h
并考虑两个索引r
和s
r
,则{li> s
出现在排列h(r) < h(s)
之前,并为100到1000个不同的哈希函数执行此操作。
醇>
我可能错过了任何已知的图书馆吗?或者你可能知道的使用python生成哈希函数族的任何标准方法?
答案 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
答案 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
中随机抽取。
基于维基百科的表述,使用可以使用以下代码:
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)