Python 中的字符串相似度

String similarity in Python

我正在尝试比较 Python 中的字符串。我的字符串包含可以采用多种不同方式构建的标题:

'Title'
'Title: Subtitle'
'Title - Subtitle'
'Title, Subtitle'
'Title Subtitle'

是否可以在Python中做相似度比较,从而确定match('Title: Subtitle', 'Title - Subtitle') = True? (或者无论如何构造)

基本上,即使拆分不同,我也在尝试确定它们是否是同一个标题。

if 'Title: Subtitle' == 'Title - Subtitle':
    match = 'True'
else:
    match = 'False'

还有一些可能存储为 The Title: The SubtitleTitle, The: Subtitle, The,尽管我认为这可能会增加一些复杂性,但我可以通过重建字符串来解决。

我是一名 Ruby 程序员,所以没有 Python 方面的经验,但是在 Ruby 中,使用 gem Levensthein 可以很快解决这样的问题。它计算您需要对一个字符串进行多少次编辑才能得到相同的字符串。

我看到还有一个 Python 等价物,所以看看 https://pypi.python.org/pypi/python-Levenshtein

您可以使用 in 关键字。这不是相似性比较,而是做你想做的:

s = "Title: Subtitle"

if "Title" in s or "Subtitle" in s:
    match = 'True'
else:
    match = 'False'

尝试替换字符,然后检查是否相等:

def match(str1, str2):
    str1 = str1.replace(' -', '').replace(',', '').replace(':', '')
    str2 = str2.replace(' -', '').replace(',', '').replace(':', '')
    return str1 == str2

>>> match('Title: Subtitle', 'Title - Subtitle')
True
>>> match('Title: Subtitle', 'Title, Subtitle')
True
>>> 

您正在尝试做的事情已经在 jellyfish 包中很好地实现了。

>>> import jellyfish
>>> jellyfish.levenshtein_distance('jellyfish', 'smellyfish')
2

这应该有效。 Python 翻译可以用来取出任何不同的字符。

titles = ['Title: Sub', 'Title Sub', 'Title - Sub']
s = ': -'

if titles[1].translate(None, s) == titles[2].translate(None, s):
    match = 'True'
else 
    match = 'False'

fnmatch.fnmatch 虽然专为 Unix 文件名匹配而设计,但在这里也很方便,请考虑以下示例:

>>> from fnmatch import fnmatch
>>> l
['Title: Subtitle', 'Title - Subtitle', 'Title, Subtitle', 'Title Subtitle']
>>>
>>> all(fnmatch(x, 'Title*Subtitle') for x in l)
True

另一种方法,将检查它们是否都匹配 re 模式:

>>> import re
>>> l
['Title: Subtitle', 'Title - Subtitle', 'Title, Subtitle', 'Title Subtitle']
>>> all(re.search(r'^Title.*?Subtitle$', x) for x in l)
True

如果唯一的障碍是标点符号,问题就微不足道了:只需丢弃 non-word 个字符并比较剩余的单词列表。

s1 = 'Title - Subtitle'
toks1 = re.split(r"^\W+", s1)  # keep just the words
toks1 = [ w.lower() for w in toks1 ]

我加入了小写字母,因为这也可能不同。将相同的应用到每个输入并比较列表。

但正如您所指出的,可能还有其他差异。如果您的数据确实包含标题(书籍、电影、科学文章),您可以像图书馆一样,先删除文章和常用连接词 (so-called "stopwords")。例如,"The title of the article" 被精简为 ["title", "article"]。要处理其他可能的词序差异,您可以使用信息检索中常见的 so-called "bag of words" 方法。将标记列表转换为一个集合,或者在某些单词出现多次的情况下转换为单词计数字典。这是一个示例,使用字数统计和 nltk 的 "stopword" 列表作为过滤器。

import nltk
from collections import Counter
stopwords = set(nltk.corpus.stopwords.words("english"))

toks1 = [ t for t in toks1 if t not in stopwords ]
cnt1 = Counter(toks1)
cnt2 = Counter(toks2)  # Another title string, processed the same way
if cnt1 == cnt2:
    print("The two strings have exactly the same content words")

如果还有更多的变化,天空是极限。近似文本匹配是一个活跃的研究主题,在信息检索、剽窃检测、遗传学等方面都有应用。您可以检查一个标题是否是另一个标题的子集(也许有人遗漏了副标题)。您可以尝试通过 "edit distance" 进行匹配(例如,其他几个答案提到的 "Levenshtein distance" ),将其应用于字母或整个单词。你可以尝试像 TF-IDF score 这样的信息检索算法。这些只是您可以尝试的一些事情,因此请寻找最简单的解决方案来完成这项工作。 Google 是你的朋友。

标准库的 difflib 模块提供了一个函数 get_close_matches 进行模糊字符串匹配。

>>> import difflib
>>> difflib.get_close_matches('python', ['snakes', 'thon.py', 'pythin'])
['pythin', 'thon.py']  # ordered by similarity score