Python (1)散列函数,(2)签名长度和(3)jaccard相似性之间的关系?
我试图在python中理解/实现基于minHash的jaccard相似性。主要目标是在MapReduce中使用它。然而,我不清楚哈希函数和签名长度的选择如何影响计算相似性时的错误率。从维基百科上,我发现与计算出的jaccard相似性相关的签名长度(K)和错误长度(e)一般为K=O(1/e^2)。我尝试在python中实现minHash:Python (1)散列函数,(2)签名长度和(3)jaccard相似性之间的关系?,python,hash-function,minhash,Python,Hash Function,Minhash,我试图在python中理解/实现基于minHash的jaccard相似性。主要目标是在MapReduce中使用它。然而,我不清楚哈希函数和签名长度的选择如何影响计算相似性时的错误率。从维基百科上,我发现与计算出的jaccard相似性相关的签名长度(K)和错误长度(e)一般为K=O(1/e^2)。我尝试在python中实现minHash: import random import sys #ERROR_THRESHOLD = 0.05 #SIG_LENGTH = int(1/(ERROR_THR
import random
import sys
#ERROR_THRESHOLD = 0.05
#SIG_LENGTH = int(1/(ERROR_THRESHOLD**2))
_memomask = {}
def hash_values(n, x):
"""Compute n different hash values"""
values = []
for i in range(n):
mask = _memomask.get(i)
if mask is None:
random.seed(i)
mask = _memomask[i] = random.getrandbits(32)
values.append((hash(str(x)) % mask))
return values
def compare_signatures(x, y):
"""Compare MinHash Signatures"""
size = len(x)
if size != len(y): raise Exception("Different signature length")
if size == 0: raise Exception("signature length is zero")
counter = 0
for i in range(size): counter += int(x[i] == y[i])
return counter/float(size)
items = [['A',3], ['A',6], ['A',9], ['B',2], ['B',4], ['B',6], ['B',8]]
for SIG_LENGTH in [1, 10, 100, 400, 1000]:
#Step 1: Compute Hash Signature for each token
data = []
for item in items:
values = hash_values(SIG_LENGTH, item[1])
key = item[0]
data.append((key, values))
#Step 2: Group by Key and compute MinHash for each index
signatures = {}
for item in data:
key = item[0]
values = item[1]
if key not in signatures: signatures[key] = [-1.0]*SIG_LENGTH
cur_signature = signatures[key]
signatures[key] = [(values[i] if cur_signature[i] == -1.0 else min(values[i], cur_signature[i])) for i in range(SIG_LENGTH)]
#Step 3: Compute Probability of minHash signature to be same
keys = signatures.keys()
key_length = len(keys)
print "Jaccard Similarity based on signature of length {0}".format(SIG_LENGTH)
for i in range(key_length):
x_key = keys[i]
x_sig = signatures[x_key]
for j in range(i+1,key_length):
y_key = keys[j]
y_sig = signatures[y_key]
print "J({0},{1}) = {2}".format(x_key, y_key, compare_signatures(x_sig, y_sig))
在我的测试中,我发现准确度随着签名长度的增加而增加,但随后开始下降(或保持稳定)。我想知道是不是因为选择了散列函数。如果是,请有人推荐一个好的散列函数使用
我找到了一些相关的帖子,但仍然不清楚:
md5和sha工作得很好:
import random
import hashlib
import sys
k = int(sys.argv[1])
salts = [random.getrandbits(32) for i in range(k)]
def h(value, salt):
m = hashlib.md5() #or hashlib.sha1()
m.update(str(value))
m.update(str(salt))
return m.digest()
def get_signatures(A):
return [min([h(x, salt) for x in A]) for salt in salts]
def compare_signatures(A, B):
"""Compare MinHash Signatures"""
sigA = get_signatures(A)
sigB = get_signatures(B)
return sum(map(lambda x: int(sigA[x] == sigB[x]), range(k)))/float(k)
A = [3,6,9]
B = [2,4,6,8]
print compare_signatures(A, B)
以及一些测试:
$ for((i=10;i<2000;i*=10)); do python minhash.py $i; done
0.2
0.14
0.163
$for((i=10;i生成大量散列函数的一种方法是使用不同的种子。就像在createHashFunctions
中,您问1)minhash算法的最佳散列数是多少;2)您是否使用了正确的散列函数
1) 你提到:k=O(1/e^2)。如果e表示错误,则这是正确的。您还可以将其表示为预期误差(epsilon)的顺序(1/k**0.5)。请记住,这是该算法将收敛的平均预期误差,而不一定是特定比较的预期误差
2) 您可以使用任何随机散列函数,只要每个散列的盐分不同。64位哈希值可能是我推荐的最小值。我会避免使用MD5或SHA,因为这里不需要这些开销。请确保按照操作系统的大小获取散列的模数,例如Python中的sys.maxsize()。如果不这样做,则会遇到算法运行不正确的实例。我已将代码内联移动。如果它太大,你应该缩小它,而不是链接到其他地方的副本。在这种情况下,尺寸很好,而且无论如何也不能缩小太多。