如何在相似度得分为 python 的大字符串中找到相似子串?
How to find a similar substring inside a large string with a similarity score in python?
我要找的不仅仅是两个文本之间的简单相似度分数。但是字符串中子字符串的相似度得分。说:
text1 = 'cat is sleeping on the mat'.
text2 = 'The cat is sleeping on the red mat in the living room'.
在上面的例子中,text1
的所有单词都完全出现在text2
中,因此相似度应该是100%。
如果text1
的部分单词缺失,则得分较低
我正在处理一个具有不同段落大小的大型数据集,因此在具有如此相似性得分的较大段落中找到较小的段落至关重要。
我只发现了比较两个字符串的字符串相似性,例如余弦相似性、difflib 相似性等。但不是关于另一个字符串中的子字符串分数。
根据您的描述,如何:
>>> a = "cat is sleeping on the mat"
>>> b = "the cat is sleeping on the red mat in the living room"
>>> a = a.split(" ")
>>> score = 0.0
>>> for word in a: #for every word in your string
if word in b: #if it is in your bigger string increase score
score += 1
>>> score/len(a) #obtain percentage given total word number
1.0
万一它有一个遗漏的词,例如:
>>> c = "the cat is not sleeping on the mat"
>>> c = c.split(" ")
>>> score = 0.0
>>> for w in c:
if w in b:
score +=1
>>> score/len(c)
0.875
此外,您可以按照@roadrunner 的建议,拆分 b
并将其保存为一组,以加快您使用 b = set(b.split(" "))
的性能。这会将该部分的复杂度降低到 O(1)
,并将整个算法提高到 O(n)
的复杂度。
编辑: 你说你已经尝试了一些指标,比如余弦相似度等。但是我怀疑你可能会从检查 Levenshtein Distance 相似度中受益,我怀疑这可能是在这种情况下,一些用途作为所提供解决方案的补充。
与 DarkCygbus 类似,但相似性是基于其总字符数而不是单词数。另一方面,这个脚本只检查了与完整单词 (text_2.split())
的一致性
from __future__ import division
text_1 = 'cat is sleeping on the mat'
text_2 = 'The cat is sleeping on the red mat in the living room'
no_match = 0
match = 0
for word in text_1.split():
if word not in text_2.split():
no_match += len(word)
else:
match += len(word)
similarity = match/(match + no_match)
print ('{0:.0%}'.format(similarity))
您还可以使用 collections.defaultdict
来存储 word_a
中存在于 word_b
中的单词计数,然后 sum()
将计数除以 word_a
最后:
from collections import defaultdict
a = "the cat is not sleeping on the mat"
b = "the cat is sleeping on the red mat in the living room"
word_a = a.split()
word_b = set(b.split())
d = defaultdict(int)
for word in word_a:
if word in word_b:
d[word] += 1
print(sum(d.values()) / len(word_a))
哪些输出:
0.875
注: 因为我们只关心检查 word_a
中的单词是否存在于 word_b
中,然后将 word_b
转换为 set()
将允许 O(1)
查找,而不是将其保留为列表,这将是 O(n)
。这就使得上述代码的整体时间复杂度O(n)
。
我要找的不仅仅是两个文本之间的简单相似度分数。但是字符串中子字符串的相似度得分。说:
text1 = 'cat is sleeping on the mat'.
text2 = 'The cat is sleeping on the red mat in the living room'.
在上面的例子中,text1
的所有单词都完全出现在text2
中,因此相似度应该是100%。
如果text1
的部分单词缺失,则得分较低
我正在处理一个具有不同段落大小的大型数据集,因此在具有如此相似性得分的较大段落中找到较小的段落至关重要。
我只发现了比较两个字符串的字符串相似性,例如余弦相似性、difflib 相似性等。但不是关于另一个字符串中的子字符串分数。
根据您的描述,如何:
>>> a = "cat is sleeping on the mat"
>>> b = "the cat is sleeping on the red mat in the living room"
>>> a = a.split(" ")
>>> score = 0.0
>>> for word in a: #for every word in your string
if word in b: #if it is in your bigger string increase score
score += 1
>>> score/len(a) #obtain percentage given total word number
1.0
万一它有一个遗漏的词,例如:
>>> c = "the cat is not sleeping on the mat"
>>> c = c.split(" ")
>>> score = 0.0
>>> for w in c:
if w in b:
score +=1
>>> score/len(c)
0.875
此外,您可以按照@roadrunner 的建议,拆分 b
并将其保存为一组,以加快您使用 b = set(b.split(" "))
的性能。这会将该部分的复杂度降低到 O(1)
,并将整个算法提高到 O(n)
的复杂度。
编辑: 你说你已经尝试了一些指标,比如余弦相似度等。但是我怀疑你可能会从检查 Levenshtein Distance 相似度中受益,我怀疑这可能是在这种情况下,一些用途作为所提供解决方案的补充。
与 DarkCygbus 类似,但相似性是基于其总字符数而不是单词数。另一方面,这个脚本只检查了与完整单词 (text_2.split())
的一致性from __future__ import division
text_1 = 'cat is sleeping on the mat'
text_2 = 'The cat is sleeping on the red mat in the living room'
no_match = 0
match = 0
for word in text_1.split():
if word not in text_2.split():
no_match += len(word)
else:
match += len(word)
similarity = match/(match + no_match)
print ('{0:.0%}'.format(similarity))
您还可以使用 collections.defaultdict
来存储 word_a
中存在于 word_b
中的单词计数,然后 sum()
将计数除以 word_a
最后:
from collections import defaultdict
a = "the cat is not sleeping on the mat"
b = "the cat is sleeping on the red mat in the living room"
word_a = a.split()
word_b = set(b.split())
d = defaultdict(int)
for word in word_a:
if word in word_b:
d[word] += 1
print(sum(d.values()) / len(word_a))
哪些输出:
0.875
注: 因为我们只关心检查 word_a
中的单词是否存在于 word_b
中,然后将 word_b
转换为 set()
将允许 O(1)
查找,而不是将其保留为列表,这将是 O(n)
。这就使得上述代码的整体时间复杂度O(n)
。