如何按条件替换字符串中spaCy识别的GPE类地理实体词汇?
问题描述
我有一个存储文本列的DataFrame,样例数据如下:
Text "Lorum Ipsum Rotterdam dolor sit." "ed ut perspiciatis Boekarest, New York, consectetur adipiscing elit, sed " "Excepteur sint occaecat Glasgow cupidatat non proident, sunt in culpa"
需求是把文本里所有地理位置实体替换为GPE。
目前用spaCy做实体检测的代码运行正常,可以正确识别出所有GPE实体:
nlp = spacy.load('en_core_web_lg') for value in df['text']: doc = nlp(value) for ent in doc.ents: print(ent.text, ent.label_)
运行输出:
Rotterdam GPE Boekarest GPE New York GPE Glasgow GPE
但自行编写的替换代码完全达不到预期效果:
for value in df['text']: doc = nlp(value) for ent in doc.ents: for word in value.split(): if ent.label_ == "GPE": word.replace(ent.label, "_GPE_")
原代码错误点
- Python字符串是不可变对象,
str.replace()方法不会修改原字符串,只会返回替换后的新字符串,上述代码既没有接收这个返回值,也没有修改原始文本内容,循环跑完原始数据不会有任何变化。 - 替换参数和逻辑完全错误:代码里写的
word.replace(ent.label, "_GPE_"),ent.label是spaCy的标签方法对象,既不是要替换的实体文本,也不是标签值;另外按空格拆分单词的方式根本处理不了New York这种多词实体,也处理不了实体后面紧跟标点(比如Boekarest,)的场景。 - 全程没有将修改后的内容写回DataFrame列,就算替换逻辑正确,DataFrame里存储的还是原始文本。
修正方案
最稳妥的替换方式是直接利用spaCy返回的实体字符偏移量做切片替换,不需要手动拆分单词,还能自动适配多词实体、带标点的实体场景。注意替换时要从文本末尾的实体开始往前替换,避免前面替换改变文本长度后,后续实体的偏移位置失效。
完整可运行代码如下:
import spacy nlp = spacy.load('en_core_web_lg') def replace_gpe_entity(text): doc = nlp(text) processed_text = text # 倒序遍历实体,避免偏移量失效 for ent in reversed(doc.ents): if ent.label_ == "GPE": # 按实体的原文字符位置切片替换,避免误替换同名字符串 processed_text = processed_text[:ent.start_char] + "*GPE*" + processed_text[ent.end_char:] return processed_text # 将处理结果写回DataFrame对应列 df['text'] = df['text'].apply(replace_gpe_entity)
处理后文本列的输出结果符合预期:
Text "Lorum Ipsum *GPE* dolor sit." "ed ut perspiciatis *GPE*, *GPE*, consectetur adipiscing elit, sed " "Excepteur sint occaecat *GPE* cupidatat non proident, sunt in culpa"
如果需要替换为HTML格式的<em>GPE</em>,只需要把代码里替换的目标字符串改成对应内容即可。
内容的提问来源于stack exchange,提问作者EvitaSchaap
相关产品推荐
相关产品推荐

