如何用spaCy结合自定义数据集与标签实现NER,识别电影评论自定义实体
用spaCy提取电影评论中的自定义实体(ACTOR、DIRECTOR等)
方案一:基于规则的实体匹配(快速上手)
如果你的评论有固定表述模式(比如"导演XXX"、"主演XXX"、"上映日期:YYYY-MM-DD"),用spaCy的Matcher可以快速实现自定义实体提取,无需训练模型。
实现代码
import spacy from spacy.matcher import Matcher # 加载spaCy中文模型(英文评论替换为'en_core_web_sm') nlp = spacy.load("zh_core_web_sm") # 初始化匹配器 matcher = Matcher(nlp.vocab) # 定义匹配规则 # 1. DIRECTOR:匹配"导演""执导"后的人名 director_patterns = [ [{"TEXT": "导演"}, {"ENT_TYPE": "PERSON", "OP": "+"}], [{"TEXT": "执导"}, {"ENT_TYPE": "PERSON", "OP": "+"}] ] # 2. ACTOR:匹配"主演""饰演"后的人名 actor_patterns = [ [{"TEXT": "主演"}, {"ENT_TYPE": "PERSON", "OP": "+"}], [{"TEXT": "饰演"}, {"ENT_TYPE": "PERSON", "OP": "+"}] ] # 3. DATE_OF_AIR:匹配"上映时间""播出日期"后的日期 date_patterns = [ [{"TEXT": "上映时间"}, {"ENT_TYPE": "DATE", "OP": "+"}], [{"TEXT": "播出日期"}, {"ENT_TYPE": "DATE", "OP": "+"}] ] # 4. AUTHOR:匹配"作者:""评论者:"后的用户名 author_patterns = [ [{"TEXT": "作者"}, {"TEXT": ":"}, {"ENT_TYPE": "PERSON", "OP": "+"}], [{"TEXT": "评论者"}, {"TEXT": ":"}, {"ENT_TYPE": "PERSON", "OP": "+"}] ] # 绑定规则与自定义实体标签 matcher.add("DIRECTOR", director_patterns) matcher.add("ACTOR", actor_patterns) matcher.add("DATE_OF_AIR", date_patterns) matcher.add("AUTHOR", author_patterns) # 实体提取函数 def extract_custom_entities(text): doc = nlp(text) matches = matcher(doc) entities = [] for match_id, start, end in matches: entity_label = nlp.vocab.strings[match_id] # 跳过触发词,只提取实体内容 if entity_label in ["DIRECTOR", "ACTOR"]: entity_text = doc[start+1:end].text elif entity_label in ["DATE_OF_AIR", "AUTHOR"]: entity_text = doc[start+2:end].text entities.append((entity_label, entity_text)) return entities # 测试示例 sample_review = "导演诺兰的新片《奥本海默》主演基里安·墨菲,上映时间2023年7月21日,作者:电影爱好者" result = extract_custom_entities(sample_review) print("提取到的自定义实体:") for label, text in result: print(f"{label}: {text}")
方案二:训练自定义NER模型(适合无固定模式的大量数据)
如果评论表述无规律,需要让模型自主学习实体特征,就需要标注数据并训练spaCy的NER组件。
步骤1:准备标注数据
标注数据格式如下(可手动整理或用Prodigy工具辅助标注):
TRAIN_DATA = [ ( "导演张艺谋的《满江红》由沈腾、易烊千玺主演,2023年1月22日上映,评论者:影评人小李", {"entities": [(2,5,"DIRECTOR"), (11,13,"ACTOR"), (15,19,"ACTOR"), (22,32,"DATE_OF_AIR"), (36,41,"AUTHOR")]} ), ( "我很喜欢卡梅隆执导的《阿凡达》,主演萨姆·沃辛顿,作者:科幻迷小王", {"entities": [(5,8,"DIRECTOR"), (16,22,"ACTOR"), (26,31,"AUTHOR")]} ) # 补充更多标注数据,样本量越多模型效果越好 ]
步骤2:训练模型代码
import spacy from spacy.training import Example from spacy.util import minibatch, compounding # 加载基础模型 nlp = spacy.load("zh_core_web_sm") # 获取或添加NER组件 if "ner" not in nlp.pipe_names: ner = nlp.add_pipe("ner", last=True) else: ner = nlp.get_pipe("ner") # 注册自定义实体标签 for label in ["DIRECTOR", "ACTOR", "DATE_OF_AIR", "AUTHOR"]: ner.add_label(label) # 冻结其他组件,仅训练NER other_pipes = [pipe for pipe in nlp.pipe_names if pipe != "ner"] with nlp.disable_pipes(*other_pipes): optimizer = nlp.begin_training() # 训练循环 for iteration in range(10): losses = {} # 打乱数据保证训练稳定性 spacy.util.fix_random_seed(42) batches = minibatch(TRAIN_DATA, size=compounding(4.0, 32.0, 1.001)) for batch in batches: for text, annotations in batch: doc = nlp.make_doc(text) example = Example.from_dict(doc, annotations) nlp.update([example], sgd=optimizer, losses=losses) print(f"迭代 {iteration+1},NER损失值:{losses['ner']:.4f}") # 保存训练好的模型 nlp.to_disk("./custom_movie_ner_model") # 测试模型效果 test_review = "冯小刚导演的《芳华》主演黄轩,2017年12月15日上映,作者:文艺青年小张" doc = nlp(test_review) print("\n训练后模型提取的实体:") for ent in doc.ents: print(f"{ent.label_}: {ent.text}")
注意事项
- 规则匹配适合句式固定的场景,训练模型适合复杂无规律的文本
- 英文评论需替换为对应英文模型(如
en_core_web_sm) - 标注数据建议至少几百条,才能保证模型泛化能力
内容的提问来源于stack exchange,提问作者mCs
相关产品推荐
相关产品推荐

