python - 有没有办法设置 spacy 的 POS 标记?
问题描述
我们有一个包含三列的 pandas 数据框:主语、动词和宾语。
- 在主题列中,数据看起来像“我”或“我们”。
- 在动词列中,它看起来像“有”或“没有”或“喜欢”。
- 在对象列中,它看起来像“真空”或“地板”。
我正在尝试用 spacy 对所有这些列进行词形还原,以添加三个新列:subject_lemma、verb_lemma 和 object_lemma。我可以用下面的代码做到这一点,但是我遇到了一些问题没有被正确地词形还原(例如,动词列中带有“loved”的单元格没有被更改为现在时态“love”,它只是保持不变)。在做了一些测试之后,我认为这是因为 spacy 将“loved”标记为形容词而不是动词。我有什么办法可以解决这个问题吗?我在想我可以将整个动词列的 pos 标记设置为动词,这样它就可以正确地对动词进行词形还原,比如“loved”,但是动词列中有一些不是动词的词(例如,不在“did”中)不是”)。
可能这里有另一篇文章解释了这一点,如果我看不到它,请见谅!非常感谢您的建议!
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”被正确识别为动词并相应地进行词形化。我的解决方案是将完整的句子传递给 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))
这告诉我们索引 1、2 和 3 inspacy_toks
处的标记属于标记 1 in raw_toks
。在下面的函数中,我用它在使用 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