【问题标题】:Get closest match between sentence(represented as string) and list of phrases获取句子(表示为字符串)和短语列表之间的最接近匹配
【发布时间】:2021-10-05 15:20:57
【问题描述】:

让我从一个例子开始。在 python 中考虑以下列表

cities = [
    'New york'
    'San francisco',
    'California',
    'Las vegas',
    'Chicago',
    'Miami'
]

我也有以下句子。

sentences = [
    "Both of us were new to New York City, and had few or no friends.",
    "Win three more games and he becomes king of San Francisco.",
    "Uncurling from the couch, she started to the bedroom of her father's small Miami apartment."
]

对于每个句子,找出该句子中最接近列表中任何字符串的子字符串。所以,在这个例子中,我想得到sentences 中每个句子的最长子字符串,它最接近cities 列表中的任何字符串。因此,在这种情况下,我的结果应该如下所示:

desired_result = [
    'New york',
    'San fransisco',
    'Miami'
]

我想到的算法很少,但并不理想。

算法 1

一种算法可以给出非常好的结果,但在时间复杂度方面却非常糟糕。我试图提取一个句子的所有子短语,从 n 单词子短语到一个带有 n 个标记的句子的一个单词子短语。然后我使用difflib.get_close_matches 函数来检测最接近cities 列表中任何字符串的任何子短语。但是,我们可以清楚地看到,复杂性非常高。对于长度为n 的句子,我们总共有O(n*n) 子短语。此外,城市名单也不小。在我的实际用例中,这个列表包含大约 700 万个字符串。

在这种情况下,我的代码如下所示:


def generate_subphrases(sen): 
    subphrases: List[str] = []
    # My logic to generate all possible subphrases
    # . 
    # . 
    # . 
    return subphrases


result = []
for sen in sentences:
    subphrases = generate_subphrases(sen)
    ans = None
    for phrase in subphrases:
        if get_close_matches(phrase, cities):
            ans = phrase
            break
    result.append(ans)

print(result)

算法2

与以前的方法相比,这有点快,但是,这不如上一种方法好。使用最后一种方法的好处是我们可以容忍这种方法中的一些不匹配。例如,如果cities 列表甚至包含New york,则会检测到New York。但是,在这种情况下,我们甚至不能容忍单个字符不匹配。在我的用例中,就字符不匹配而言,我可以容忍高达 30-35% 的错误。在这种方法中,我用列表中所有城市的联合形成了巨大的正则表达式。然后我使用re.search 在我的句子中搜索子短语。在我看来,这更快但不是很好。

我想知道我是否可以使用任何数据结构来完成这项任务,或者任何类似于difflib.get_close_matches 的python 实用函数可以允许搜索整个句子。

更新

我的最终目标是让算法 1 更有效,可能是使用一些我可能不熟悉的字符串算法,或者可能是一些数据结构。我也曾经想过 `Trie` 数据结构,但同样,这有助于精确匹配,而不是算法 1 中描述的 python 实用函数提供的软匹配。

注意:在这种情况下,我没有执行 NER 任务。提供的示例只是为了轻松说明问题。出于这个原因,我不能使用像 Spacy 或 NLTK 这样的预训练机器学习模型来识别城市。总体目标不是识别城市,而是识别字符串中最接近字符串列表中任何字符串的子短语

【问题讨论】:

  • 你为什么要告诉我们两个算法,如果你想知道与你发布的代码相关的东西,根据你写的,它属于第一个算法?
  • 也许看看 NLTK 包realpython.com/nltk-nlp-python -- nltk.org
  • @user1934428,我试图展示我是如何尝试解决这个问题的。现在我还认为,在我的用例中,算法 2 可能是一个不正确的解决方案。抱歉发布第二个算法。我想更有效地实现我在算法 1 中所做的事情,可能使用一些数据结构或高效算法。
  • @Ruchit :在您的问题中指出您想要提高代码的哪一部分,以及您考虑了哪些替代方案。
  • @user1934428,添加了更新。我想让算法 1 更高效

标签: python-3.x string algorithm longest-substring


【解决方案1】:

如果您可以在运行算法之前创建可能的匹配字符串,pyahocorasick 将是您的用例的完美解决方案,因为它会预先计算您尝试匹配的所有城市的 trie。

缺点是您需要提供变体/可能的字符不匹配模式。

对于您的幼稚算法 1,我建议仅返回大小不超过 M 的子短语,其中 M 是您拥有的字符串列表中最长的标记。 (例如,尝试将 10 个单词的子句与最多 3 个单词的字符串进行匹配是没有意义的)。这至少应该有助于加快速度。

【讨论】:

  • 是的。限制长度肯定会有很大帮助。感谢您提供有关pyahocorasick 的建议。我会检查一下。
  • 虽然查看了我的数据,但发现列表中也包含更长的词组,最长可达 5 到 7 个。这是不同公司的产品名称列表。
猜你喜欢
  • 2019-09-22
  • 2011-08-17
  • 1970-01-01
  • 1970-01-01
  • 2017-03-29
  • 1970-01-01
  • 1970-01-01
  • 2014-11-18
  • 2022-01-19
相关资源
最近更新 更多