【问题标题】:Find matching phrases and words in a string python在字符串python中查找匹配的短语和单词
【发布时间】:2014-09-22 15:21:48
【问题描述】:

使用 python,从给定字符串中提取常用短语或单词的最有效方法是什么?

例如,

string1="once upon a time there was a very large giant called Jack"
string2="a very long time ago was a very brave young man called Jack"

会返回:

["a","time","there","was a very","called Jack"] 

如何有效地做到这一点(在我的情况下,我需要在数千个 1000 字的文档中做到这一点)?

【问题讨论】:

  • 我认为这里不需要正则表达式。
  • 效率会因开发人员而异,具体取决于您询问的对象。但是在您的情况下,我会说在列表中混合使用单个单词和短语并不是很有效。也许将每个单词存储到数据库中(或创建自己的数据类型)并跟踪之前和之后出现的每个单词......这对你来说可能非常有效,也可能不是。

标签: python string nlp


【解决方案1】:

你可以split每个字符串,然后intersectsets。

string1="once upon a time there was a very large giant called Jack"
string2="a very long time ago was a very brave young man called Jack"
set(string1.split()).intersection(set(string2.split()))

结果

set(['a', 'very', 'Jack', 'time', 'was', 'called'])

请注意,这仅匹配单个单词。您必须更具体地说明您认为“短语”的内容。最长连续匹配子串?这可能会变得更复杂。

【讨论】:

  • 我认为“最长的连续匹配子串”符合我的意思。
  • 请注意set.intersection 采用任意可迭代对象,因此仅使用string2.split() 不需要显式的set 调用
  • @JonClements 我不知道,谢谢你的提示!
【解决方案2】:

在自然语言处理中,您通常使用n-grams 从句子中提取常见模式和序列。 在 python 中,您可以使用出色的 NLTK 模块。

要计算和查找最常见的,您可以使用collections.Counter

以下是 2-gram 的示例:

from nltk.util import ngrams
from collections import Counter
from itertools import chain

string1="once upon a time there was a very large giant called Jack"
string2="a very long time ago was a very brave young man called Jack"

n = 2
ngrams1= ngrams(string1.split(" "), n)
ngrams2= ngrams(string2.split(" "), n)

counter= Counter(chain(ngrams1,ngrams2))       #count occurrences of each n-gram
print [k[0] for k,v in counter.items() if v>1] #print all ngrams that come up more than once

输出:

[('called', 'Jack'), ('was', 'a'), ('a', 'very')]

使用n=3 输出:

[('was', 'a', 'very')]

使用n=1 输出(不含元组):

['Jack', 'a', 'was', 'time', 'called', 'very']

【讨论】:

  • 您可以使用 nltk.word_tokenize() 而不是 str.split(),这将解释标点符号。
【解决方案3】:

这是一个经典的动态规划问题。您需要做的就是为string1 构建一个后缀树,使用单词而不是字母(这是通常的表述)。这是illustrative example of a suffix tree

  1. 将树中的所有节点标记为s1
  2. 一一插入string2的所有后缀。
  3. 第 2 步中后缀经过的所有节点都标记为 s2
  4. 在第 2 步中创建的任何新节点也都标记为 s2
  5. 在最终的树中,标记为s1s2 的每个节点的路径标签是一个公共子字符串。

这个算法在this lecture note中有简洁的解释。

对于长度为nm 的两个字符串,后缀树构造采用O(max(n,m)),并且所有匹配的子字符串(在您的情况下是单词或短语)都可以在O(#matches) 中搜索。

【讨论】:

    【解决方案4】:

    几年后,我用下面的“计数器”尝试了这种方式:

    输入[ ]:

    from collections import Counter
    
    string1="once upon a time there was a very large giant called Jack"
    string2="a very long time ago was a very brave young man called Jack"
    string1 += ' ' + string2
    string1 = string1.split()
    
    count = Counter(string1)
    tag_count = []
    for n, c in count.most_common(10):
        dics = {'tag': n, 'count': c}
        tag_count.append(dics)
    
    

    输出[]:

    [{'tag': 'a', 'count': 4},
     {'tag': 'very', 'count': 3},
     {'tag': 'time', 'count': 2},
     {'tag': 'was', 'count': 2},
     {'tag': 'called', 'count': 2},
     {'tag': 'Jack', 'count': 2},
     {'tag': 'once', 'count': 1},
     {'tag': 'upon', 'count': 1},
     {'tag': 'there', 'count': 1},
     {'tag': 'large', 'count': 1}]
    

    希望它对某人有用:)

    【讨论】:

      猜你喜欢
      • 2023-03-11
      • 1970-01-01
      • 2016-11-02
      • 2018-07-11
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多