有没有办法设置 spacy 的 POS 标记?

Is there a way to set spacy's POS tagging?

我们有一个包含三列的 pandas 数据框:主语、动词和宾语。

我正在尝试使用 spacy 对所有这些列进行词形还原以添加三个新列:subject_lemma、verb_lemma 和 object_lemma。我可以用下面的代码做到这一点,但我遇到的问题是有些事情没有被正确地词形还原(例如,动词列中带有“loved”的单元格没有被更改为现在时“love”,它只是保持不变)。在做了一些测试之后,我认为这是因为“loved”被 spacy 标记为形容词而不是动词。我有办法解决这个问题吗?我在想我可以将整个动词列的 pos 标签设置为动词,这样它就可以正确地对像“loved”这样的动词进行词形还原,但是动词列中有些词不是动词(例如不在“did”中不是”)。

这里可能还有另一个 post 对此进行了解释,如果我看不到,请见谅!非常感谢您的建议!

import pandas as pd
import spacy
nlp = spacy.load('en_core_web_trf')

def spacy_lemmatizer(text):
    doc = nlp(text)
    lemmatized_sentence = " ".join([token.lemma_ for token in doc])
    return(lemmatized_sentence)

dataframe.loc[:,'subject_lemma'] = dataframe.loc[:,'subject'].apply(spacy_lemmatizer)
dataframe.loc[:,'verb_lemma'] = dataframe.loc[:,'verb'].apply(spacy_lemmatizer)
dataframe.loc[:,'object_lemma'] = dataframe.loc[:,'object'].apply(spacy_lemmatizer)

首先要注意的是词形还原 并不总是 正确。但是,在您的情况下,问题更大的是它是上下文相关的操作。在句子的上下文中,“loved”被正确识别为动词并相应地进行词形还原。我的解决方案是将 complete 句子传递给 SpaCy,然后将生成的引理重新映射到原始标记化,这需要更多的工作,但在词形还原方面应该会得到最好的结果。

1。重新加入和 nlp-ing 句子

df = pd.DataFrame.from_records([['He', 'loved', 'floors'],
                                ['I', 'don\'t like', 'vacuums']], columns=['subject', 'verb', 'object'])

df['raw_tokens'] = df[['subject', 'verb', 'object']].values.tolist()
df['doc'] = df.raw_tokens.agg(' '.join).apply(nlp)
  subject        verb   object                raw_tokens                          doc
0      He       loved   floors       [He, loved, floors]          (He, loved, floors)
1       I  don't like  vacuums  [I, don't like, vacuums]  (I, do, n't, like, vacuums)

2。对齐两个标记

我们需要将 doc 列变成一个引理列表,稍后我们可以在 保留原始标记化 的同时对其进行重组。实现此目的的一种方法是使用 SpaCy 的内置 Alignment 模块。给定两个具有不同标记化的标记列表,这将为您提供一个列表到另一个索引的映射,例如

from spacy.training import Alignment

raw_toks = ['I', "don't like", 'vacuums']
spacy_toks = ['I', 'do', "n't", 'like', 'vacuums']

alignment = Alignment.from_strings(raw_toks, spacy_toks)

# [0, 1, 2, 3, 4]
print(list(alignment.x2y.dataXd))

# [0, 1, 1, 1, 2]
print(list(alignment.y2x.dataXd))

这告诉我们 spacy_toks 中索引 1、2 和 3 处的标记属于 raw_toks 中的标记 1。在下面的函数中,我使用它在使用 SpaCy 处理后将标记映射到原始标记化,但我们收集的不是标记字符串,而是引理。这个想法是将上面的 spacy_toks 之类的输入转换为 [['I'], ['do', "n't", 'like'], ['vacuum']].

from spacy.training import Alignment
from itertools import groupby

def lemmatize(row):
    
    tokens, lemmas = zip(*((x.text, x.lemma_) for x in row.doc))
    lemmas = iter(lemmas) # so we can use next()
    
    # get alignment of surface token strings 
    alignment = Alignment.from_strings(row.raw_tokens, tokens).y2x.dataXd
    lemma_map = list()
    
    # collect lemmas into subgroups
    for _,g in groupby(alignment):
        lemma_map.append([next(lemmas) for _ in g])
    
    return [' '.join(w) for w in lemma_map]

3。将其应用于数据框

df['lemmas'] = df.apply(lemmatize, axis=1)

# some cleaning
df[['subject_lemma', 'verb_lemma', 'object_lemma']] = pd.DataFrame(df.lemmas.tolist(), index=df.index)

最终结果:

  subject        verb   object subject_lemma   verb_lemma object_lemma
0      He       loved   floors            he         love        floor
1       I  don't like  vacuums             I  do n't like       vacuum