SpaCy 提取形容词,它位于动词之前,既不是停用词也不是标点符号

SpaCy extraction of an adjective, that precede a verb and isn't a stop word nor a punctuation

我想从一个网站上抓取的评论列表中提取一组特定的单词来计算它们,并在我的 TextBlob 字典中使用最常见的单词,这将用于简单的情感分析。为简化起见:我想获得所有可能具有正面或负面情绪的形容词。 komentarze 是一个巨大的字符串列表,每个字符串都是一个句子,我想检查哪个情绪。 我想从这个字符串列表中创建一个单词列表,然后检查哪些形容词(既不是标点符号也不是停用词并且位于动词之前)是最常见的。当我 运行 我的代码时,我得到一个错误: IndexError: [E040] Attempt to access token at 18, max length 18. 这个错误代表 尝试在 {i} 处访问令牌,最大长度为 {max_length}。 我尝试了不同的代码,但其中 none 有效。

这是一个想要继续但给出 E040 错误的代码示例:

import spacy
import json
import pandas as pd
from spacy.lang.pl.stop_words import STOP_WORDS
from spacy.tokens import Token
from spacy.lang.pl.examples import sentences
from collections import Counter

with open('directory/file.json', mode='r') as f:
    dane = json.load(f)

df = pd.DataFrame(dane)
komentarze = df['komentarz'].tolist()

nlp = spacy.load('pl_core_news_lg')
slowa = []
zwroty = []

for doc in nlp.pipe(komentarze):
    #here I want to extract most common words
    slowa += [token.text for token in doc if not token.is_stop and not token.is_punct]
    #here I want to extract adjs, that are not puncts nor stop-words and are before a verb.
    zwroty += [token.text for token in doc if (not token.is_stop and not token.is_punct and 
    token.pos_ == "ADJ" and doc[token.i + 1].pos_ == "VERB")]

zwroty_freq = Counter(zwroty)
common_zwroty = zwroty_freq.most_common(100)
print(common_zwroty)

在循环中我 运行 一个额外的 adjsy += [token.text for token in doc if (not token.is_stop and not token.is_punct and token.pos_ == "ADJ")] 时,一切正常,但我无法在 ADJ.

之前或之后指定单词

我可以通过以下方式迭代一个简单的字符串:

for token in doc:
    if token.pos_ == 'ADJ':
        if doc[token.i + 1].pos_ == 'VERB':
            print('yaaay’)

但我真的不知道如何在我的循环中设置它。 我也试过:

   for token in doc:
        if not token.is_stop and not token.is_punct:
            if token.pos_ == "ADJ":
                if doc[token.i+1].pos_ == "NOUN" in range(1):
                    zwroty += token.text

但这只给了我字母。

如何解决我的问题以获得我想要的东西?

是否也可以在这个循环中将文本越低?试了好几次都没用……

已编辑: 我按照@polm23 的提议修改了我的代码。嗯,它有效,但我无法将此方法与我的 [w.lemma_ for w in doc if not w.is_stop and not w.is_punct and not w.like_num and w.pos_ == "VERB"] 列表理解结合起来,这给了我一个错误:ValueError: [E195] Matcher can be called on Doc or Span only, got Token.

这是一段代码,感谢@polm23,它可以工作,但考虑了数字、标点符号等:

import everything I need

with open('file.json', mode='r') as f:
    dane = json.load(f)

df = pd.DataFrame(dane)
komentarze = df['komentarz'].tolist()

nlp = spacy.load('pl_core_news_lg')
matcher = Matcher(nlp.vocab)
patterns = [[{'POS':'ADJ'}, {'POS':'NOUN'}]]
matcher.add("demo", patterns)

zwroty =[]

for doc in nlp.pipe(komentarze):
    matches = matcher(doc)

    for match_id, start, end in matches:
        string_id = nlp.vocab.strings[match_id]
        span = doc[start:end]
        zwroty += (match_id, string_id, start, end, span.text)

这是一段代码,它不起作用,但是,应该考虑到这一点:

    for w in doc:
        if not w.is_stop and not w.is_punct:
            w.lemma_

            matches = matcher(w)
            for match_id, start, end in matches:
                string_id = nlp.vocab.strings[match_id]
                span = w[start:end]
                zwroty += (match_id, string_id, start, end, span.text)

这是 spaCy Matchers 的完美用例。下面是一个匹配英文ADJ NOUN的例子:

import spacy
from spacy.matcher import Matcher

nlp = spacy.load("en_core_web_sm")

matcher = Matcher(nlp.vocab)

patterns = [
    [{'POS':'ADJ'}, {'POS':'NOUN'}],
    ]
matcher.add("demo", patterns)

doc = nlp("There is a red card in the blue envelope.")
matches = matcher(doc)
for match_id, start, end in matches:
    string_id = nlp.vocab.strings[match_id]  # Get string representation
    span = doc[start:end]  # The matched span
    print(match_id, string_id, start, end, span.text)

输出:

2193290520773312886 demo 3 5 red card
2193290520773312886 demo 7 9 blue envelope

如果需要,您可以在 Counter 或其他东西中使用这些匹配项来跟踪频率。您还可以设置一个函数以 运行 每当匹配时。

Is it also possible the lower the text in this loop? I tried several times, but nothing worked…

不完全确定你想做什么,但如果你有匹配功能,你可以只使用令牌上的 lower_ 属性。也看看 lemma_,这可能更好,尤其是对于动词。


不完全确定我理解你想做什么,但看起来问题是你正在尝试过滤标记,然后将它们传递给匹配器。相反,使用文档上的匹配器,然后过滤其输出。

此外,标点符号永远不能成为形容词,我不确定您为什么要检查它。

out = []
for doc in docs:
    matches = matcher(doc)
    # because we are just matching [ADJ NOUN] we know the first token is ADJ
    for match_id, start, end in matches:
        string_id = nlp.vocab.strings[match_id]
        adj = doc[start]
        # ignore stop words
        if adj.is_stop: continue
        # get the lemma
        lemma = adj.lemma_

        out += (adj, lemma) # or whatever