Python关系抽取怎么实现

wen python案例 2

本文目录导读:

Python关系抽取怎么实现

  1. 基于规则的关系抽取(入门级)
  2. 基于依存句法分析(进阶级)
  3. 基于预训练模型(专业级)
  4. 使用开源工具(快速实现)
  5. 完整的项目实现方案
  6. 选择建议
  7. 注意事项

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))

选择建议

方法 优点 缺点 适用场景
规则匹配 简单、快速 覆盖度低 固定格式、小规模
依存句法 可处理复杂句 依赖分词质量 中等规模、结构清晰
预训练模型 准确率高 需要标注数据 大规模、通用领域
开源工具 开箱即用 定制性差 快速原型、标准场景

注意事项

  1. 中文分词:中文关系抽取依赖高质量分词
  2. 实体识别:先做NER再做RE效果更好
  3. 长文本处理:需要分段或滑动窗口
  4. 关系重叠:一个句子可能存在多个关系
  5. 评估指标:准确率、召回率、F1分数

建议先从规则方法开始,根据效果逐步升级到深度学习方案。

抱歉,评论功能暂时关闭!