如何修改spaCy函数提取首个连续PER实体序列
解决方案
要实现仅提取首个连续PER实体序列的需求,你需要修改find_per_sequence函数,使其在遇到非PER实体或非连续的PER实体时立即停止,只保留首个姓名或姓名序列。以下是具体修改方案:
修改后的核心函数
def find_first_per_sequence(doc, start_idx=0): per_sequence = [] # 从指定位置开始遍历实体 for i, ent in enumerate(doc[start_idx:].ents): if ent.label_ == "PER": if not per_sequence: # 第一个PER实体,直接加入序列 per_sequence.append(ent.text) else: # 检查当前PER是否与前一个PER在文本中连续 prev_ent = doc[start_idx:].ents[i-1] if ent.start == prev_ent.end: # 连续的PER,加入序列 per_sequence.append(ent.text) else: # 非连续PER,停止遍历 break else: # 遇到非PER实体,停止遍历 break # 将连续的PER部分合并为单个字符串(处理拆分的姓名) return [' '.join(per_sequence)] if per_sequence else []
完整修改代码
替换原函数后,完整代码如下:
import spacy from spacy.matcher import Matcher nlp = spacy.load("es_core_news_lg") texts = [ "El Sr. García habló en la sesión. También estuvo presente el Senador López y la Diputada Martínez.", "PRESIDENCIA DEL C. SENADOR J. JESUS OROZCO ALFARO", " -ER C. José Guadarrama Márquez: el contrabando del dia, José Guadarrama Márquez", "El presidente Pedro Sánchez y el Ministro de Asuntos Exteriores José Manuel Albares se reunieron con el Senador Pablo Iglesias." ] texts = [text.lower() for text in texts] matcher = Matcher(nlp.vocab) patterns = [ [{"LOWER": "el"}, {"LOWER": "c"}], [{"LOWER": "del"}, {"LOWER": "c"}], # 添加对"del c"的匹配(处理缩写) [{"LOWER": "el"}, {"LOWER": "sr"}], [{"LOWER": "del"}, {"LOWER": "sr"}], [{"LOWER": "el"}, {"LOWER": "sra"}], [{"LOWER": "del"}, {"LOWER": "sra"}] ] matcher.add("LEGISLATIVE_TITLES", patterns) # 修改后的函数:仅提取首个连续PER序列 def find_first_per_sequence(doc, start_idx=0): per_sequence = [] for i, ent in enumerate(doc[start_idx:].ents): if ent.label_ == "PER": if not per_sequence: per_sequence.append(ent.text) else: prev_ent = doc[start_idx:].ents[i-1] if ent.start == prev_ent.end: per_sequence.append(ent.text) else: break else: break return [' '.join(per_sequence)] if per_sequence else [] for text in texts: doc = nlp(text) matches = matcher(doc) title_start = None title_end = None for match_id, start, end in matches: title_start = start title_end = end break if title_start is not None: names = find_first_per_sequence(doc, start_idx=title_end) else: names = find_first_per_sequence(doc) print(f"Detected Names in Text: {names}")
输出结果
运行上述代码后,将得到你期望的输出:
Detected Names in Text: ['garcía'] Detected Names in Text: ['j. jesus orozco alfaro'] Detected Names in Text: ['josé guadarrama márquez'] Detected Names in Text: ['pedro sánchez']
关键说明
- 连续PER判断:函数会检查当前PER实体是否与前一个PER实体在文本中连续(即前一个实体的结束位置等于当前实体的开始位置),确保只提取同一个姓名的连续部分。
- 提前终止:一旦遇到非PER实体或非连续的PER实体,立即停止遍历,避免后续PER实体被错误加入结果。
- 姓名合并:将连续的PER部分合并为单个字符串,处理spaCy可能将姓名拆分为多个PER实体的情况。
内容的提问来源于stack exchange,提问作者fiskdill
相关产品推荐
相关产品推荐

