本文目录导读:

Python中实现关系抽取(Relation Extraction, RE)有多种方法,从简单的规则匹配到基于深度学习的模型,下面我会按难度递增的方式介绍几种主流实现方案。
基于规则的关系抽取(入门级)
适合数据规模小、关系类型固定的场景。
import re
import spacy
# 加载模型
nlp = spacy.load("zh_core_web_sm")
def rule_based_re(text):
doc = nlp(text)
relations = []
# 简单规则:找出"生于"、"位于"等关系词
patterns = [
{"relation": "出生地", "pattern": r"(\w+)生于(\w+)"},
{"relation": "位于", "pattern": r"(\w+)位于(\w+)"},
]
for pattern in patterns:
matches = re.findall(pattern["pattern"], text)
for match in matches:
relations.append({
"subject": match[0],
"relation": pattern["relation"],
"object": match[1]
})
return relations
# 测试
text = "爱因斯坦生于德国,普林斯顿位于美国。"
print(rule_based_re(text))
# 输出: [{'subject': '爱因斯坦', 'relation': '出生地', 'object': '德国'},
# {'subject': '普林斯顿', 'relation': '位于', 'object': '美国'}]
基于依存句法分析(进阶级)
利用句法结构提取更复杂的关系。
import spacy
nlp = spacy.load("zh_core_web_sm")
def dependency_based_re(text):
doc = nlp(text)
relations = []
for sent in doc.sents:
# 找出主谓宾结构
for token in sent:
# 识别"是"类型的谓词
if token.dep_ == "ROOT" and token.pos_ == "VERB":
subjects = [child for child in token.children if child.dep_ == "nsubj" or child.dep_ == "nsubjpass"]
objects = [child for child in token.children if child.dep_ == "dobj" or child.dep_ == "pobj"]
for subj in subjects:
for obj in objects:
relations.append({
"subject": subj.text,
"relation": token.text,
"object": obj.text
})
return relations
# 测试
text = "李明是北京大学的教授。"
print(dependency_based_re(text))
基于预训练模型(专业级)
使用BERT等预训练模型进行关系分类。
1 安装依赖
pip install transformers torch
2 基于BERT的关系分类示例
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
class BertRE:
def __init__(self, model_name="bert-base-chinese"):
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForSequenceClassification.from_pretrained(
model_name,
num_labels=10 # 根据你的关系类型数量设置
)
def prepare_input(self, text, entity1, entity2):
"""将句子和实体对编码为模型输入"""
# 标记实体位置
marked_text = text.replace(
entity1, f"[E1]{entity1}[/E1]"
).replace(
entity2, f"[E2]{entity2}[/E2]"
)
return self.tokenizer(
marked_text,
padding="max_length",
truncation=True,
max_length=128,
return_tensors="pt"
)
def predict(self, text, entity1, entity2):
"""预测关系类型"""
inputs = self.prepare_input(text, entity1, entity2)
with torch.no_grad():
outputs = self.model(**inputs)
predictions = torch.softmax(outputs.logits, dim=-1)
return predictions
# 使用示例
re_model = BertRE()
text = "华为技术有限公司成立于1987年"
result = re_model.predict(text, "华为技术有限公司", "1987年")
print(result)
使用开源工具(快速实现)
1 使用DeepKE
pip install deepke
from deepke.relation_extraction import *
# 加载预训练模型
model = RELoader()
model.load_pretrained("bert-base-chinese")
# 预测关系
predictor = RE.predictor(model)
result = predictor.predict(
sentence="史蒂夫·乔布斯创立了苹果公司",
heads=["史蒂夫·乔布斯"],
tails=["苹果公司"]
)
print(result)
2 使用HanLP
pip install hanlp
import hanlp
# 加载预训练模型
HanLP = hanlp.load(hanlp.pretrained.mtl.CLOSE_TOK_POS_NER_SRL_DEP_SDP_CON_ELECTRA_BASE_ZH)
def extract_relations(text):
doc = HanLP(text)
relations = []
# 提取语义依赖关系
for sent in doc["sentences"]:
for relation in sent.get("srl", []):
relations.append({
"predicate": relation.get("predicate"),
"arguments": relation.get("arguments", [])
})
return relations
# 测试
text = "李明在北京大学学习计算机科学。"
print(extract_relations(text))
完整的项目实现方案
这里是一个结合多种方法的实用方案:
import json
from typing import List, Dict
import spacy
from transformers import pipeline
class RelationExtractor:
def __init__(self, method="hybrid"):
self.method = method
self.nlp = spacy.load("zh_core_web_sm")
if method == "ml":
# 使用HuggingFace的关系抽取pipeline
self.classifier = pipeline(
"text-classification",
model="bert-base-chinese"
)
def extract_entities(self, text: str) -> List[Dict]:
"""实体识别"""
doc = self.nlp(text)
entities = []
for ent in doc.ents:
entities.append({
"text": ent.text,
"label": ent.label_,
"start": ent.start_char,
"end": ent.end_char
})
return entities
def extract_relations_rule(self, text: str) -> List[Dict]:
"""基于规则的简单关系抽取"""
doc = self.nlp(text)
relations = []
# 常见关系模式
relation_patterns = {
"生育": ["生于", "诞生", "出生"],
"属于": ["属于", "隶属", "归属"],
"包含": ["包含", "包括", "含有"],
"位于": ["位于", "坐落", "地处"],
}
for token in doc:
if token.text in [v for vals in relation_patterns.values() for v in vals]:
# 获取主语和宾语
subj = list(token.lefts)[0].text if token.lefts else None
obj = list(token.rights)[0].text if token.rights else None
if subj and obj:
relations.append({
"subject": subj,
"relation": token.text,
"object": obj
})
return relations
def extract(self, text: str) -> Dict:
"""主抽取方法"""
result = {
"text": text,
"entities": self.extract_entities(text),
"relations": []
}
if self.method == "rule":
result["relations"] = self.extract_relations_rule(text)
elif self.method == "ml":
# 这里可以集成机器学习方法
pass
else: # hybrid
# 结合多种方法
rule_relations = self.extract_relations_rule(text)
result["relations"] = rule_relations
return result
# 使用示例
extractor = RelationExtractor(method="rule")
text = "阿里巴巴集团成立于1999年,总部位于杭州。"
result = extractor.extract(text)
print(json.dumps(result, ensure_ascii=False, indent=2))
选择建议
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 规则匹配 | 简单、快速 | 覆盖度低 | 固定格式、小规模 |
| 依存句法 | 可处理复杂句 | 依赖分词质量 | 中等规模、结构清晰 |
| 预训练模型 | 准确率高 | 需要标注数据 | 大规模、通用领域 |
| 开源工具 | 开箱即用 | 定制性差 | 快速原型、标准场景 |
注意事项
- 中文分词:中文关系抽取依赖高质量分词
- 实体识别:先做NER再做RE效果更好
- 长文本处理:需要分段或滑动窗口
- 关系重叠:一个句子可能存在多个关系
- 评估指标:准确率、召回率、F1分数
建议先从规则方法开始,根据效果逐步升级到深度学习方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播