大数据系统与大规模数据分析学习笔记(相似度计算)
寻找相似项过程:
1. Jaccard相似度
定义 Jaccard 相似度计算公式:J(A,B)=(A交B)/(A并B)
2. shingling
- 将文档用短字符集合来表示
2.1 k-shingle
- character 级别:包括空格
- word 级别:不包括空格和逗号句号符
2.2 k 值大小的选择
- 如果文档由邮件组成,那么选择 k = 5 比较合适。
- 如果文档比较大,选择 k = 9 比较合适
3. Min Hashing (最小哈希)算法
属于lsh的一种,当两个向量能求Jaccard相似度时可用此方法,Jaccard相似度=交集/并集,MH主要作用是压缩。通过Min-Hashing,我们就可以把句子的高维one-hot向量转化为一个低维的指纹向量,而且能够保证指纹向量之间的相似度约等于未转换前one-hot向量之间的相似度。
3.1 特征矩阵
特征矩阵的一列就对应一个集合,所有的行加起来就是所有集合元素的全集,如果集合中有那个元素,则矩阵中的对应位置为1,否则为0。
3.2 最小哈希
构建集合的特征矩阵是为了计算集合的最小哈希。
为了计算最小哈希,首先对特征矩阵的行进行打乱(也即随机调换行与行之间的位置),这个打乱是随机的。然后某一列的最小哈希值就等于打乱后的这一列第一个值为1的行所在的行号,行号从0开始。
3.3哈希签名矩阵(Signature Matrix)
当数据量大时,求相似度,耗时会很大,我们需要对数据进行处理,我们使用Min hashing(最小哈希)将集合的特征矩阵,转变成签名矩阵。对于哈希签名矩阵,每列第一个哈希值相等的概率与Jaccard 相似度相同,可以近似求Jaccard 相似度。
其实得到上面的签名矩阵之后,我们就可以用签名矩阵中列与列之间的相似度来计算集合间的Jaccard相似度了;但是这样会带来一个问题,就是当一个特征矩阵很大时(假设有上亿行),那么对其进行行打乱是非常耗时,更要命的是还要进行多次行打乱。为了解决这个问题,可以通过一些随机哈希函数来模拟行打乱的效果。
4. 局部敏感哈希算法(LSH)
通过上面的方法处理过后,一篇文档可以用一个很小的签名矩阵来表示,节省下很多内存空间;但是,还有一个问题没有解决,那就是如果有很多篇文档,那么如果要找出相似度很高的文档,其中一种办法就是先计算出所有文档的签名矩阵,然后依次两两比较签名矩阵的相似度;这样做的缺点是当文档数量很多时,要比较的次数会非常大。那么我们可不可以只比较那些相似度可能会很高的文档,而直接忽略过那些相似度很低的文档。接下来我们就讨论这个问题的解决方法。
首先,我们可以通过上面的方法得到一个签名矩阵,然后把这个矩阵划分成b个行条(band),每个行条由r行组成。对于每个行条,存在一个哈希函数能够将行条中的每r个整数组成的列向量(行条中的每一列)映射到某个桶中。可以对所有行条使用相同的哈希函数,但是对于每个行条我们都使用一个独立的桶数组,因此即便是不同行条中的相同列向量,也不会被哈希到同一个桶中。这样,只要两个集合在某个行条中有落在相同桶的两列,这两个集合就被认为可能相似度比较高,作为后续计算的候选对;而那些在所有行条中都不落在同一个桶中的两列,就会被认为相似度不会很高,而被直接忽略。下面直接看一个例子:
例如,现在有一个12行签名矩阵,把这个矩阵分为4个行条,每个行条有3行;为了方便,这里只写出行条1的内容。
可以看出,行条1中第2列和第4列的内容都为[0,2,1],所以这两列会落在行条1下的相同桶中,因此无论在剩下的3个行条中这两列是否有落在相同桶中,这两个集合都会成为候选对。在行条1中不相等的两列还有另外的3次机会成为候选对,因为他们只需在剩下的3个行条中有一次相等即可。
经过上面的处理后,我们就找出了相似度可能会很高的一些候选对,接下来我们只需对这些候选队进行比较就可以了,而直接忽略那些不是候选对的集合。这个方法适合用来计算相似度超过某个值的文档的相似度,而不适用于计算所有文档的相似度,因为那些相似度可能很低的文档已经被直接忽略了。
计算相似度超过某个值的文档的相似度,而不适用于计算所有文档的相似度,因为那些相似度可能很低的文档已经被直接忽略了。