如何将for循环内spaCy提取的名词结果作为DataFrame新增列
核心错误点
你的代码无法正常运行,是几个写法错误导致的:
- 每次循环处理单条文本时,都执行
dataset["Noun"] = xxx对全列赋值,会直接覆盖之前所有行的处理结果,最终全列只会保留最后一条文本的提取值 dataset.assign(nouns.values)属于API用法错误:assign的作用是返回带新列的新DataFrame,入参必须是列名=值的键值对格式,不能直接传入数组- 把Matcher初始化、规则添加的逻辑写在循环里,会重复创建对象拖慢运行速度;且
sentence = doc后又执行doc = nlp(sentence)属于冗余操作,doc对象不需要再传入nlp重复处理 - 匹配规则用
{'POS': 'NOUN', 'OP': '?'}表示匹配0或1个名词,会产生大量空匹配结果,不符合提取名词的需求
修正后可运行代码
把公共初始化逻辑移到循环外,用列表暂存每一行的提取结果,循环结束后一次性给新列赋值即可:
import spacy from spacy.matcher import Matcher from spacy.util import filter_spans # 模型、匹配器只初始化一次,不要放在循环里 nlp = spacy.load("en_core_web_lg") matcher = Matcher(nlp.vocab) # 匹配规则调整为匹配1个及以上连续名词,避免空匹配;如果只需要提取单个名词,直接去掉OP参数即可 pattern = [{'POS': 'NOUN', 'OP': '+'}] matcher.add("Noun phrase", [pattern]) result_nouns = [] # 直接遍历文本列,不需要用iloc按索引取值 for txt in dataset["Text"]: doc = nlp(txt) matches = matcher(doc) spans = [doc[start:end] for _, start, end in matches] filtered_nouns = filter_spans(spans) # 两种存储格式二选一: # 1. 用逗号拼接成字符串存储 current_noun = ", ".join([span.text for span in filtered_nouns]) # 2. 存为列表格式:current_noun = [span.text for span in filtered_nouns] result_nouns.append(current_noun) # 所有行处理完后一次性赋值新列 dataset["Noun"] = result_nouns
额外提示
- 不要在for循环中对DataFrame整列赋值,这种写法不仅会覆盖结果,运行效率也极低
- 提取名词时记得取Span对象的
.text属性拿到实际字符串,不要直接存spaCy的Span对象,否则后续做DataFrame序列化、导出操作时会报错 - 如果需要匹配更复杂的名词短语,可以调整pattern规则,比如加上形容词、限定词的匹配逻辑
内容的提问来源于stack exchange,提问作者Andrzej
相关产品推荐
相关产品推荐

