t1 = 'This is an example data for testing minhashing'
t2 = 'This is an example test data for minhashing'
t3 = 'This is not related at all'
t4 = t1
t5 = t3
# texts = [t1,t2,t3,t4,t5]
texts = [t1,t2,t3,t4,t5]
# Define Shingling function
def shingle(s, l):
#Generate k-tuple shingles of a string
l = min(len(s), l)
return([s[i:i+l] for i in range(len(s) - l + 1)])
# Declare punctuation
exclude = set(string.punctuation)
# Generate hash functions
def hash_functions():
def hash_factory(ni):
return(lambda x: hash("salt" + str(ni) + str(x) + "salt"))
return [hash_factory(i) for i in range(2)]
# Create list of shingle lists and Normalize text
shingle_list = [shingle(''.join(ch for ch in d.lower().replace(' ','') if ch not in exclude),4) for d in texts]
for x in shingle_list:
print x
# Generate LSH matrix
LIST = [[min(fn(t) for t in tuples) for i, fn in enumerate(hash_functions())] for tuples in shingle_list]
for x in LIST:
print x
任何人都可以解释一下上面代码片段中提到的哈希函数,它工作正常但我不理解(“salt”+ str(ni)+ str(x)+“salt)。
答案 0 :(得分:2)
它工作正常,但我不理解(“盐”+ str(ni)+ str(x)+“盐)。
这部分是微不足道的。
首先,str
函数接受任何对象并将其转换为字符串表示形式。例如,ni
将是一个0
或1
,str
将转换为字符串"0"
或"1"
。< / p>
接下来,我们将四个字符串连接在一起:"a" + "bc" + "d" + "ef"
为您提供"abcdef"
。
我猜你真的问为什么你会这样做。
当您根据更简单的哈希函数为某些值组合编写哈希函数时,您需要小心确保包含某种“salting”,因此您的特殊值组合不会意外地将哈希值与相同值的简单组合相同。
对于一个更简单的例子,请考虑这个类:
class Point(object):
def __init__(self, x, y):
self.x, self.y = x, y
def __hash__(self):
return hash((self.x, self.y))
但这意味着hash((1.0, 2.0)) == hash(Point(1.0, 2.0))
。通常,你不希望这样; Point与元组不是同一个东西,它是一个具有自己的(非常薄,但不是不存在)语义的类型。因此,您将一些额外的值(称为“salt”)添加到哈希中。例如:
class Point(object):
def __init__(self, x, y):
self.x, self.y = x, y
def __hash__(self):
return hash((type(self), self.x, self.y))
现在,hash((1.0, 2.0)) != hash(Point(1.0, 2.0))
。
请注意,这与盐渍哈希的其他重要原因不同,但并非无关(例如,在加密哈希中,您可以协商一些共享随机值以用作盐,以确保没有人可以重现相同的哈希结果,除非他们有协商的盐,你可以使用密钥交换协议来确保他们没有它。)
然而,值得一提的是,这是一个非常愚蠢的哈希函数。
首先,散列值元组比使用连接字符串更简单,更健壮,更有效。很可能这段代码是为其他语言编写的,这些语言没有通用hash
函数,只有hash_string
函数。
第二,如果你不相信你所依赖的hash
函数,那么你想要同时添加和添加盐而不仅仅是其中一种盐的唯一原因就是它的部分值均匀。而且,如果你不能相信这一点,那么把盐放在两端并没有多大帮助 - 实际上可能会受到伤害。 (例如,如果你的hash_string
低估了前几个字符之后的所有内容,那么预先加上盐可以很好地避免与未加值的值发生冲突,同时附加它也不会 - 但这也意味着你要推出4个以上的实际字符对于输入的高估部分,所以你的盐渍哈希比普通哈希更加分散。如果你真的不能相信哈希函数,你就不能建立一个更复杂的哈希函数。它;你必须建立自己的。
答案 1 :(得分:1)
您突出显示的部分
def hash_functions():
def hash_factory(ni):
return(lambda x: hash("salt" + str(ni) + str(x) + "salt"))
return [hash_factory(i) for i in range(2)]
是功能工厂。而不是hash_factory
返回一个值,它返回一个函数,其中,erm,函数取决于您传递它的值。想象一下:
def greeting_factory(greeting):
return lambda name: greeting + name
您可以使用此问候语创建其他功能,例如:
say_hola = greeting_factory("Hola, ")
say_bonjour = greeting_factory("Bonjour, ")
say_hello = greeting_factory("Hello, ")
say_howdy = greeting_factory("Howdy, ")
然后使用每个THOSE函数,这些函数都期望一个参数(该人的名字要问好)
>>> say_hola("Juan")
Hola, Juan
>>> say_bonjour("Jacques")
Bonjour, Jacques
>>> say_hello("James")
Hello, James
>>> say_howdy("pardner")
Howdy, pardner
在这种情况下,它使用函数工厂构建一些不同的散列函数,然后返回列表。这与:
相同def ways_to_say_hello():
def greeting_factory(greeting):
return lambda name: greeting + name
return [greeting_factory(greet) for greet in ['Hola, ', 'Bonjour, ',
'Hello, ', 'Howdy, ']]
>>> for hello_func in ways_to_say_hello():
... hello_func("Adam Smith")
Hola, Adam Smith
Bonjour, Adam Smith
Hello, Adam Smith
Howdy, Adam Smith