详解用于相似和抄袭检测的技术Shingling 原创
本文将向你介绍shingling的概念、Shingling技术的基础知识、Jaccard相似性、以及高级技术和优化。
在数字时代,信息随时可用且易于访问,需要一种能够检测抄袭(有意或无意)的技术,从内容复制到增强自然语言处理能力。Shingling的功能与众不同之处在于它扩展到各种应用程序的方式,包括但不限于文档集群、信息检索和内容推荐系统。
本文概述了以下内容:
- 理解Shingling的概念
- 探索Shingling的基础知识
- Jaccard相似度:测量文本相似度
- 高级技术和优化
- 结论及进一步阅读
一、 理解Shingling的概念
Shingling技术是一种广泛用于检测和减轻文本相似性的技术。它是将文档中的一串文本转换为一组重叠的单词或字母序列的过程。在编程上,可以将其看作是字符串值中的子字符串列表。
让我们举个例子:“Generative AI is evolving rapidly.”。我们用k表示Shingle 的长度,并将k的值设为5。
结果是一组五个字母:
{'i is ', ' evol', 'apidl', 'e ai ', 'ai is', 'erati', 've ai', 'rapid', 'idly.', 'ing r', ' ai i', 's evo', 'volvi', 'nerat', ' is e', 'ving ', 'tive ', 'enera', 'ng ra', 'is ev', 'gener', 'ative', 'evolv', 'pidly', ' rapi', 'olvin', 'rativ', 'lving', 'ive a', 'g rap'}
这组重叠的序列被称为“shingles”或“n-grams”。Shingles由文本中连续的单词或字符组成,创建了一系列重叠的片段。上面称为“k”的Shingle的长度根据分析的具体要求而不同,常见的做法是创建包含三到五个单词或字符的shingles。
二、 探索Shingling的基本知识
Shingling是三步骤过程的一部分。
标记化
如果你熟悉提示式工程,那么应该听说过标记化。它是将一系列文本分解成被称为标记的更小单位的过程。标记可以是单词、子词、字符或其他有意义的单位。此步骤为模型的进一步处理准备了文本数据。通过单词标记化,上面的例子“Generative AI is evolving rapidly”将被标记化为:
['Generative', 'AI', 'is', 'evolving', 'rapidly', '.']
对于标记化,你可以使用简单的Python的split方法或Regex方法。有像NLTK(自然语言工具包)和spaCy这样的库提供停用词等高级选项。
Shingling
正如现在所知的,Shingling,也被称为n-gramming,是从标记文本中创建一组连续的标记序列(n-grams or shingles)的过程。例如,使用k=3,句子“Generative AI is evolving rapidly.”将会生成如下shingles:
[['Generative', 'AI', 'is'], ['AI', 'is', 'evolving'], ['is', 'evolving', 'rapidly.']]
ingling有助于捕捉此时的词序和上下文。
哈希(Hashing)
哈希仅仅意味着使用特殊的函数将任何类型的数据,如文本或shingles,转换为固定大小的代码。一些流行的哈希方法包括MinHash、SimHash和局部敏感哈希(LSH)。哈希支持对类似的文本段进行高效的比较、索引和检索。当你将文档转换成一组shingles代码时,比较它们并发现相似之处或可能的剽窃要简单得多。
简单的Shingling
让我们看看两个被广泛用于解释简单shingling的短文:
00001● 第一段:“The quick brown fox jumps over the lazy dog.”
00002● 第二段:“The quick brown fox jumps over the sleeping cat.”
k值大小为4,使用上面的w-shingle Python,第1段的shingles是:
Shell
1
python w_shingle.py "The quick brown fox jumps over the lazy dog." -w 4
[['The', 'quick', 'brown', 'fox'], ['quick', 'brown', 'fox', 'jumps'], ['brown', 'fox', 'jumps', 'over'], ['fox', 'jumps', 'over', 'the'], ['jumps', 'over', 'the', 'lazy'], ['over', 'the', 'lazy', 'dog.']]
对于第2段,shingles应为:
Shell
1
python w_shingle.py "The quick brown fox jumps over the sleeping cat" -w 4
[['The', 'quick', 'brown', 'fox'], ['quick', 'brown', 'fox', 'jumps'], ['brown', 'fox', 'jumps', 'over'], ['fox', 'jumps', 'over', 'the'], ['jumps', 'over', 'the', 'sleeping'], ['over', 'the', 'sleeping', 'cat']]
通过比较shingles组,你可以看到前四个shingles是相同的,这表明了两个短文之间的高度相似性。
Shingling为更详细的分析奠定了基础,比如使用Jaccard相似性来衡量相似性。选择合适的shingle尺寸“k”是至关重要的。较小的shingle可以捕捉小的语言细节,而较大的shingle可能显示更大的画面联系。
三、 Jaccard相似性:测量文本相似性
在文本分析中,Jaccard相似度被认为是一个关键的度量指标。通过两个样本中共享的shingles数量与唯一的shingle总数的比率,来计算两个样本之间的相似性。
J(A,B) = (A ∩ B) / (A ∪ B)
Jaccard相似度定义为交集的大小除以每个文本的组合集的大小。虽然听起来简单明了,但这种技术非常强大,因为它提供了一种计算文本相似度的方法,可以根据两段文本的内容了解它们之间的关系有多密切。使用Jaccard相似性使研究人员和人工智能模型能够精确地比较文本数据的分析。它用于文档聚类、相似性检测和内容分类等任务。
Shingling也可以用来将相似的文档聚类在一起。通过将每个文档表示为一组碎片并计算这些集合之间的相似性(例如,使用Jaccard系数或余弦相似性),你可以将具有高相似性分数的文档分组到簇中。这种方法在各种应用程序中都很有用,比如搜索引擎结果聚类、主题建模和文档分类。
在Python等编程语言中实现Jaccard相似性时,选择单字大小(k)和转换为小写字母确保了比较的一致基础,展示了该技术在识别文本相似性方面的实用性。
让我们计算两个句子之间的Jaccard相似度:
Python
def create_shingles(text, k=5):
"""Generates a set of shingles for given text."""
return set(text[i : i + k] for i in range(len(text) - k + 1))
def compute_jaccard_similarity(text_a, text_b, k):
"""Calculates the Jaccard similarity between two shingle sets."""
shingles_a = create_shingles(text_a.lower(), k)
print("Shingles for text_a is ", shingles_a)
shingles_b = create_shingles(text_b.lower(), k)
print("Shingles for text_b is ", shingles_b)
intersection = len(shingles_a & shingles_b)
union = len(shingles_a | shingles_b)
print("Intersection - text_a ∩ text_b: ", intersection)
print("Union - text_a ∪ text_b: ", union)
return intersection / union
示例
text_a = "Generative AI is evolving rapidly."
text_b = "The field of generative AI evolves swiftly."
shingles_a = {'enera', 's evo', 'evolv', 'rativ', 'ving ', 'idly.', 'ative', 'nerat', ' is e', 'is ev', 'olvin', 'i is ', 'pidly', 'ing r', 'rapid', 'apidl', 've ai', ' rapi', 'tive ', 'gener', ' evol', 'volvi', 'erati', 'ive a', ' ai i', 'g rap', 'ng ra', 'e ai ', 'lving', 'ai is'}
shingles_b = {'enera', 'e fie', 'evolv', 'volve', 'wiftl', 'olves', 'rativ', 'f gen', 'he fi', ' ai e', ' fiel', 'lves ', 'ield ', ' gene', 'ative', ' swif', 'nerat', 'es sw', ' of g', 'ftly.', 'ld of', 've ai', 'ves s', 'of ge', 'ai ev', 'tive ', 'gener', 'the f', ' evol', 'erati', 'iftly', 's swi', 'ive a', 'swift', 'd of ', 'e ai ', 'i evo', 'field', 'eld o'}
J(A,B) = (A ∩ B) / (A ∪ B) = 12 / 57 = 0.2105
所以,Jaccard的相似度是0.2105。得分表示两组相似度为21.05 %(0.2105 * 100)。
示例
让我们来看看两组数字,而不是段落:
A = { 1,3,6,9}
B = {0,1,4,5,6,8}
(A∩B)=两个集合中的公共数= {1,6} = 2
(A∪B)=集合的总数={0、1、3、4、5、6、8、9}=8
计算Jaccard相似度,看看这两组数字有多相似:
(A ∩ B) / (A ∪ B) = 2/8 = 0.25
要计算差异,只需从1中减去这个相似度的值。
1- 0.25 = 0.75
所以这两组的情况,相似是25%,不同是75%。
四、 高级技术和优化
先进的拼接、哈希技术和优化,对于在大型数据集中进行高效的相似检测和抄袭检测至关重要。以下是一些高级技术和优化,以及示例和代码实现链接:
局部敏感哈希(LSH)
位置敏感哈希(LSH)是一种先进的技术,它提高了相似性检测的叠加和哈希效率。它涉及到创建一个签名矩阵,并使用多个哈希函数来降低数据的维数,从而有效地找到类似的文档。
LSH背后的关键思想是将相似的项目以高概率散列到同一个桶(bucket)中,而不相似的项目散列到不同的桶(bucket)中。这是通过使用一系列LSH来实现的,这些散列函数将相似的项散列到相同值的概率高于不相似的项。
示例
看以下两个文件A和B,用一组shingles表示:
- 文件A: {"the quick brown", "quick brown fox", "brown fox jumps"}
- 文件 B: {"a fast brown", "fast brown fox", "brown fox leaps"}
我们可以通过以下方式应用LSH:
- 使用多个哈希函数生成签名矩阵。
- 使用哈希函数对每个shingle进行哈希,以获得签名向量。
- 将特征向量分成频带。
- 哈希每个波段以获得桶密钥(bucket key)。
- 具有同样桶密钥(bucket key)的文档被认为是相似度的潜在候选。
这一过程显著减少了需要进行比较的文档对的数量,使相似度检测更有效。
最小哈希(minhashing,也称散列)
最小哈希是一种通过使用一组散列函数来快速估计两个集合之间相似性的技术。它通常应用于大规模数据处理任务,在这些任务中,计算集合之间的精确相似性的计算成本是很高的。最小散列近似于集合之间的Jaccard相似性,它测量两个集合之间的重叠。
以下是最小哈希的工作原理:
生成签名矩阵
- 给定一组项目,将每个项目表示为一组shingle。
- 构造一个签名矩阵,其中每一行对应一个哈希函数,每一列对应一个shingle。
- 将哈希函数应用于集合中的每个shingle,并且对于每个哈希函数,在矩阵的相应行中记录第一个shingle为1(最小值)的索引。
估计相似性
- 为了估计这两个集合之间的相似性,请比较它们各自的签名矩阵。
- 计算签名一致的位置的数量(即,两个集对该哈希函数具有相同的最小哈希值)。
- 将协议的计数除以哈希函数的总数来估计Jaccard相似度。
最小哈希允许显著减少表示集合所需的数据量,同时提供它们相似度的良好近似值。
示例:两个集合
- 集合A= {1、2、3、4、5}
- 集合B = {3、4、5、6、7}
我们可以用shingles来表示这些集合:
- 集合A shingle: {1, 2, 3}, {2, 3, 4}, {3, 4, 5}, {4, 5}, {5}
- 集合B shingle:{3, 4}, {4, 5}, {5, 6}, {6, 7}, {3}, {4}, {5}, {6}, {7}
现在,让我们使用散列生成签名矩阵:
现在,让我们估计集合A和B之间的相似性:
- 协议数量=2(适用于Shingle 3和Shingle 5)
- 哈希函数总数=3
- Jaccard相似度≈2/3≈0.67
代码实现:你可以使用NumPy和datasketch等库在Python中实现最小哈希。
Banding 和 Bucketing
Banding和Bucketing是与最小哈希结合使用的高级优化技术,可有效识别大型数据集中的相似集。在处理大量文档或数据点时,这些技术尤其有价值。
Banding
Banding是将散列签名矩阵分成多个带,每个带包含几行。通过将矩阵垂直划分为带,我们减少了集合之间需要的比较次数。我们只比较同一频带内的行,而不是比较整个矩阵中的每对行。这大大减少了计算开销,特别是对于大型数据集,因为我们一次只需要考虑一个子集的行。
Bucketing
Bucketing通过进一步缩小每个波段内的比较过程来补充波段。在每个带内,我们将行散列到固定数量的桶(bucket)中。每个桶(bucket)都包含Banding中带的行子集。在比较集合的相似性时,我们只需要比较每个带内哈希到同一桶(bucket)的集合对。这大大减少了所需的成对比较次数,使过程更加高效。
示例
假设我们有一个100行和20个波段的散列(Minhash)签名矩阵。在每个带内,我们将行散列到10个桶(bucket)中。在比较集合时,不需要比较所有100行,我们只需要比较每个带(band)内散列到同一桶(bucket)的集合对。这大大减少了所需的比较次数,从而显著提高了性能,特别是对于大型数据集。
收益
- 效率:Banding和Bucketing大大减少了所需的成对比较次数,使相似性分析在计算上更加高效。
- 可扩展性:这些技术能够处理由于计算限制而不切实际的大型数据集。
- 内存优化:通过减少比较Banding和Bucketing的次数,也降低了内存需求,使过程更高效。
一些开源软件提供了shingling、minhashing将LSH与Bucketing结合的功能,如Python中的datasketch库和Java中的lsh库。
候选配对
候选配对是一种高级技术,与shingling和minhashing结合使用,可实现高效的抄袭检测和近乎重复的识别。在shingling的上下文中,候选配对的工作方式如下:
Shingling
文档首先被转换成k-shingles集合,k-shingles是从文本中提取的k个标记(单词或字符)的连续序列。这个步骤将文档表示为重叠的k-gram集,从而实现相似性比较。
最小哈希(Minhashing,也称散列)
然后使用散列技术将shingles集转换为紧凑的散列签名,这些签名是固定长度的向量。散列签名保持文档之间的相似性,允许有效地估计Jaccard相似性。
Banding
散列签名被分成多个波段,每个波段是原始签名的一个较小的子向量。
Bucketing
在每个带(band)内,使用散列函数将子向量散列到桶(bucket)中。具有特定频带相同散列值的文档被放置在同一存储桶(bucket)中。
候选配对生成
如果两个文档在所有频带上共享至少一个桶(bucket),则将它们视为相似性比较的候选对。换句话说,如果它们的子向量在至少一个频带(band)内碰撞,它们被认为是候选对。
使用候选对的优点主要是它大大减少了需要比较相似性的文档对的数量,因为只考虑候选对。这使得抄袭检测过程更加有效,特别是对于大型数据集。
通过仔细选择频带数和频带大小,可以在相似性检测的准确性和计算复杂度之间做出权衡。频带越多,精度越高,但也会增加计算成本。
文档相似性
结论
综上所述,shingling、minhashing、banding和Locality Sensitive Hashing (LSH)的结合为大型文档集合中的抄袭检测和近重复识别提供了一种强大而有效的方法。
Shingling将文档转换为k-shingles集合,k-shingles是k个标记(单词或字符)的连续序列,支持相似性比较。然后,散列(Minhashing)将这些块集压缩成紧凑的签名,保持文档之间的相似性。
为了进一步提高效率,将散列(Minhashing)签名分成多个带,并将每个带的散列分成桶(bucket),将相似的文档分组在一起。这个过程生成候选对,候选对是在所有频带上共享至少一个桶(bucket)的文档对,这大大减少了需要比较相似性的文档对的数量。
然后只对候选对执行实际的相似性计算,使用原始的散列签名来估计Jaccard相似性。相似度高于特定阈值的配对被认为是潜在的抄袭案例或近重复。
这种方法有几个优点:
- 可伸缩性:通过关注候选对,计算复杂性大大降低,使处理大型数据集成为可能。
- 准确性:Shingling和Minhashing即使在内容被改写或重新排序时也能检测到抄袭,因为它们依赖于重叠的k- shings。
- 灵活性:频带(band)数量和频带(band)大小的选择允许在准确性和计算复杂性之间进行权衡,从而实现针对特定用例的优化。
一些开源软件,如Python中的datasketch库和Java中的lsh库,提供了shingling、minhashing将LSH与Bucketing结合的功能,使这些技术更容易集成到剽窃检测系统或其他需要高效相似性搜索的应用程序中。
总的来说,Shingling、Minhashing、Banding和LSH的结合为抄袭检测和近重复识别提供了一个强大而有效的解决方案,可应用于学术界、出版和内容管理系统。
进一步阅读
- 文集中的抄袭选择
- 使用datasketch的最小哈希
- chrisjmccormick/MinHash:Python实现教程
- MinHashing - Kaggle:对散列的全面探索
- 堆栈溢出讨论:对散列实现的建议
译者介绍
涂承烨,51CTO社区编辑,省政府采购专家、省综合性评标专家、公 E 采招标采购专家,获得信息系统项目管理师、信息系统监理师、PMP,CSPM-2等认证,拥有15年以上的开发、项目管理、咨询设计等经验。对项目管理、前后端开发、微服务、架构设计、物联网、大数据、咨询设计等较为关注。
原文标题:Shingling for Similarity and Plagiarism Detection,作者:Vidyasagar (Sarath Chandra) Machupalli FBCS