You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为spaCy NER模型创建基于Plotly的评估混淆矩阵

混淆矩阵生成的数据集选择

  • 必做:测试集混淆矩阵。这是评估模型泛化能力的核心依据,能直接反映模型对未见过数据的实体识别偏差,是效果评估的核心产出。
  • 选做:训练集混淆矩阵。仅当你需要排查过拟合问题、校验训练集标注质量时才需要生成,对比两个数据集的混淆矩阵差异,可以快速定位泛化性差的实体类别、或者过拟合问题。常规评估不需要每轮都生成训练集混淆矩阵,会拖慢训练速度。

具体实现路径

核心逻辑是基于spaCy的Example结构对齐真值标注和模型预测结果,逐token提取BIO格式的实体标签,统计混淆矩阵后用Plotly做可视化,所有结果可以直接同步到你现有的MLflow实验跟踪流程里。

前置依赖

提前导入用到的库即可:

from sklearn.metrics import confusion_matrix
import plotly.express as px
import numpy as np

代码修改(兼容现有训练/测试逻辑)

你现有代码里的testing函数已经构造了Example列表、调用了nlp.evaluate(),只需要在这个函数里追加标签收集、混淆矩阵计算、可视化的逻辑即可,不需要改动训练循环的核心结构。
修改后的testing函数代码:

def testing(testing_data, nlp, iteration_index):
    testing_examples = []
    for text, annotations in testing_data:
        doc = nlp.make_doc(text)
        testing_examples.append(Example.from_dict(doc, annotations))

    # 原有指标计算逻辑
    scorer_example = nlp.evaluate(testing_examples)
    del scorer_example["ents_per_type"]
    mlflow.log_metrics(scorer_example, step=iteration_index)

    # 以下为新增的混淆矩阵计算逻辑
    # 1. 定义BIO格式标签列表,直接复用你已有的CLASSES实体列表即可
    label_list = CLASSES
    bio_labels = ["O"]
    for label in label_list:
        bio_labels.extend([f"B-{label}", f"I-{label}"])
    
    # 2. 逐样本逐token收集真值和预测标签
    y_true = []
    y_pred = []
    for example in testing_examples:
        for ref_token, pred_token in zip(example.reference, example.predicted):
            # 拼接真值标签
            true_tag = "O" if ref_token.ent_iob_ == "O" else f"{ref_token.ent_iob_}-{ref_token.ent_type_}"
            # 拼接预测标签
            pred_tag = "O" if pred_token.ent_iob_ == "O" else f"{pred_token.ent_iob_}-{pred_token.ent_type_}"
            y_true.append(true_tag)
            y_pred.append(pred_tag)
    
    # 3. 计算混淆矩阵,按行归一化展示每个真实类别的预测分布
    cm = confusion_matrix(y_true, y_pred, labels=bio_labels)
    cm_normalized = cm.astype("float") / cm.sum(axis=1)[:, np.newaxis]
    cm_normalized = np.nan_to_num(cm_normalized) # 处理测试集中未出现的类别导致的除0问题

    # 4. Plotly可视化并记录到MLflow
    fig = px.imshow(
        cm_normalized,
        x=bio_labels,
        y=bio_labels,
        color_continuous_scale="Blues",
        labels=dict(x="预测标签", y="真实标签", color="样本占比"),
        text_auto=".2f"
    )
    fig.update_layout(title=f"NER测试集混淆矩阵(迭代轮次{iteration_index})")
    mlflow.log_figure(fig, f"test_confusion_matrix_iter_{iteration_index}.html")

如果需要生成训练集混淆矩阵,直接把训练数据传入上述逻辑即可,代码不需要做任何改动。

可选调整

  • 如果你不需要BIO细粒度的混淆矩阵,想直接按实体类别统计(忽略B/I边界前缀),只需要把标签拼接逻辑改成直接取ent_type_即可,标签列表替换为["O"] + CLASSES。
  • 不需要每轮迭代都生成混淆矩阵,可以加个判断,比如每5轮、或者最后一轮训练的时候再触发计算,减少训练耗时。
  • 如果混淆矩阵中某一行全为0,说明对应实体类别在当前测试集中没有标注样本,需要检查数据集拆分的类别分布是否均衡。

内容的提问来源于stack exchange,提问作者Alter__

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 18:48:28