【问题标题】:Find all words in a sentence related to a keyword查找与关键字相关的句子中的所有单词
【发布时间】:2022-01-02 20:59:17
【问题描述】:

我有以下文本,想隔离与关键字相关的句子的一部分,在本例中为keywords = ['pizza', 'chips']

text = "The pizza is great but the chips aren't the best"

预期输出:

{'pizza': 'The pizza is great'}
{'chips': "the chips aren't the best"}

我尝试过使用Spacy Dependency Matcher,但我承认我不太确定它是如何工作的。我为chips 尝试了以下模式,但没有产生匹配项。

import spacy
from spacy.matcher import DependencyMatcher

nlp = spacy.load("en_core_web_sm")

pattern = [
  {
    "RIGHT_ID": "chips_id",
    "RIGHT_ATTRS": {"ORTH": "chips"}
  },
    
  {
    "LEFT_ID": "chips_id",
    "REL_OP": "<<",
    "RIGHT_ID": "other_words",
    "RIGHT_ATTRS": {"POS": '*'}
  }
]

matcher = DependencyMatcher(nlp.vocab)
matcher.add("chips", [pattern])

doc = nlp("The pizza is great but the chips aren't the best")
for id_, (_, other_words) in matcher(doc):
    print(doc[other_words])

编辑

补充例句:

example_sentences = [
    "The pizza's are just OK, the chips is stiff and the service mediocre",
    "Then the mains came and the pizza - these we're really average - chips had loads of oil and was poor",
    "Nice pizza freshly made to order food is priced well, but chips are not so keenly priced.",
    "The pizzas and chips taste really good and the Tango Ice Blast was refreshing"
]

【问题讨论】:

  • 您需要处理的句子在结构上是否与您使用的示例相似?
  • 是的,提供的例句很好地代表了我需要处理的文本。我已经用更多例句更新了这个问题。
  • 我可以发布一个初步的解决方案,这样我们都可以检查一下吗?我的解决方案适用于您输入的第一句话和一些例句,但我们可能需要以某种方式修改其他一些例句,然后 SpaCy 才能有效地处理它们
  • 看起来您正在简化句子以进行基于方面的情感分析。 spaCy 为您提供了执行此操作的工具,但如果您以前不熟悉这些问题,它会有点涉及。我建议查看 Jurafsky 和 ​​Martin 的书(免费在线)关于依赖解析和情感分析的部分。开始。 web.stanford.edu/~jurafsky/slp3

标签: python nlp nltk spacy


【解决方案1】:

这是我对您的问题的一个非常有限的解决方案的尝试,因为我不知道您希望它有多广泛。

我使用来自this answer 的代码来解决问题。

import spacy
import re

en = spacy.load('en_core_web_sm')

text = "The pizza is great but the chips aren't the best"

doc = en(text)

seen = set() # keep track of covered words

chunks = []
for sent in doc.sents:
    heads = [cc for cc in sent.root.children if cc.dep_ == 'conj']

    for head in heads:
        words = [ww for ww in head.subtree]
        for word in words:
            seen.add(word)
        chunk = (' '.join([ww.text for ww in words]))
        chunks.append( (head.i, chunk) )

    unseen = [ww for ww in sent if ww not in seen]
    chunk = ' '.join([ww.text for ww in unseen])
    chunks.append( (sent.root.i, chunk) )

chunks = sorted(chunks, key=lambda x: x[0])


output_dict = {}

for np in doc.noun_chunks:
    insensitive_the = re.compile(re.escape('the '), re.IGNORECASE)
    new_np = insensitive_the.sub('',np.text)
    output_dict[new_np]=''

for ii, chunk in chunks:
    #print(ii, chunk)
    for key in output_dict:
        if key in chunk:
            output_dict[key]=chunk

print(output_dict)

我得到的输出是:

我知道有几个问题:

  1. 连词“but”不应出现在 Pizza 键的值中。
  2. 单词“are n't”应该不在字典的第二个值中。

但是,如果我们了解有关您正在处理的句子类型的更多信息,我相信我们可以解决此问题。例如,我们可能有一个连词列表,如果句子足够简单,我们可以从 dict 的所有值中删除。

更新例句:

如您所见,我认为 SpaCy 在标点符号方面有些吃力,并且知道您可能只想将食物作为字典中的名词。

【讨论】:

    【解决方案2】:

    您可以使用以下功能:

    def spliter(text : str , keyword :list, number_of_words:int):
        L = text.split()
        sentences = dict()
        for k in L :
            if k in keyword :
                n = L.index(k)
                if len(L) -n -1 > number_of_words :
                    sentences.update({k:' '.join(L[n : n + number_of_words])})
                else :
                    sentences.update({k:' '.join(L[n :])})
        return sentences
    

    注意: number_of_word 定义你想在想要的关键字之后得到多少字

    输出: number_of_words = 3 你得到:

    {'pizza': 'pizza is great', 'chips': "chips aren't the best"}
    

    【讨论】:

    • 不幸的是,这不适合我的用例,因为 number_of_words 参数是静态的。这种方法会因句子结构不同而失败。
    猜你喜欢
    • 1970-01-01
    • 2020-01-23
    • 1970-01-01
    • 1970-01-01
    • 2011-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-20
    相关资源
    最近更新 更多