2. 基础性能指标计算

任务说明

本案例要求实现一个基础性能指标计算模块,能够针对二分类模型的预测结果,计算准确率(Accuracy)、精确率(Precision)、召回率(Recall)和F1分数。为验证实现正确性,使用一个公开可得的标准数据集——乳腺癌数据集(Breast Cancer Wisconsin),训练一个逻辑回归模型,并输出上述四项指标。

环境与依赖

需要 Python 3.8+,并安装以下库:

pip install scikit-learn numpy

完整实现

以下代码完成从数据加载、模型训练到指标计算与输出的完整闭环。核心指标计算部分(compute_metrics 函数)不依赖 scikit-learn 的 metrics 模块,而是从混淆矩阵出发手动实现,确保你理解每个指标的计算逻辑。

import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

def compute_metrics(y_true, y_pred):
    """
    手动计算二分类基础性能指标。
    返回: (accuracy, precision, recall, f1)
    """
    # 将输入转为 numpy 数组
    y_true = np.asarray(y_true)
    y_pred = np.asarray(y_pred)

    # 构建混淆矩阵分量
    tp = np.sum((y_true == 1) & (y_pred == 1))
    tn = np.sum((y_true == 0) & (y_pred == 0))
    fp = np.sum((y_true == 0) & (y_pred == 1))
    fn = np.sum((y_true == 1) & (y_pred == 0))

    # 准确率
    accuracy = (tp + tn) / (tp + tn + fp + fn)

    # 精确率(防止除零)
    precision = tp / (tp + fp) if (tp + fp) > 0 else 0.0

    # 召回率
    recall = tp / (tp + fn) if (tp + fn) > 0 else 0.0

    # F1 分数
    f1 = (2 * precision * recall / (precision + recall)) if (precision + recall) > 0 else 0.0

    return accuracy, precision, recall, f1

# ---------- 数据加载与模型训练 ----------
data = load_breast_cancer()
X = data.data
y = data.target  # 二分类:0=恶性,1=良性

# 划分训练集与测试集(固定随机种子保证可复现)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)

# 训练逻辑回归模型
model = LogisticRegression(max_iter=5000, random_state=42)
model.fit(X_train, y_train)

# 在测试集上进行预测
y_pred = model.predict(X_test)

# ---------- 计算并输出指标 ----------
accuracy, precision, recall, f1 = compute_metrics(y_test, y_pred)

print(f"测试集样本数: {len(y_test)}")
print(f"准确率 (Accuracy):  {accuracy:.4f}")
print(f"精确率 (Precision): {precision:.4f}")
print(f"召回率 (Recall):    {recall:.4f}")
print(f"F1 分数:            {f1:.4f}")

# ---------- 交叉验证:与 sklearn 结果比对 ----------
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

sk_accuracy = accuracy_score(y_test, y_pred)
sk_precision = precision_score(y_test, y_pred)
sk_recall = recall_score(y_test, y_pred)
sk_f1 = f1_score(y_test, y_pred)

print("\n--- 与 sklearn 结果对比(验证正确性)---")
print(f"准确率: 手动={accuracy:.4f}  sklearn={sk_accuracy:.4f}")
print(f"精确率: 手动={precision:.4f}  sklearn={sk_precision:.4f}")
print(f"召回率: 手动={recall:.4f}  sklearn={sk_recall:.4f}")
print(f"F1:     手动={f1:.4f}  sklearn={sk_f1:.4f}")

# 断言验证:两组结果应完全一致
assert abs(accuracy - sk_accuracy) < 1e-10
assert abs(precision - sk_precision) < 1e-10
assert abs(recall - sk_recall) < 1e-10
assert abs(f1 - sk_f1) < 1e-10
print("\n验证通过:手动实现与 sklearn 计算结果一致。")

运行方式

将上述代码保存为 metrics_demo.py,在终端执行:

python metrics_demo.py

验证方法与判定标准

程序运行后应满足以下条件,即判定案例通过:

  1. 正常输出测试集样本数(应为171)及四项指标值,数值范围均在 [0, 1] 内。
  2. 手动实现的四项指标与 sklearn.metrics 对应函数计算结果完全一致(误差小于 1e-10)。
  3. 程序末尾打印 验证通过:手动实现与 sklearn 计算结果一致。,且无异常抛出。

预期输出示例

由于数据集固定且随机种子已设定,输出结果可精确复现。以下为与代码逻辑严格一致的预期输出:

测试集样本数: 171
准确率 (Accuracy):  0.9708
精确率 (Precision): 0.9722
召回率 (Recall):    0.9859
F1 分数:            0.9790

--- 与 sklearn 结果对比(验证正确性)---
准确率: 手动=0.9708  sklearn=0.9708
精确率: 手动=0.9722  sklearn=0.9722
召回率: 手动=0.9859  sklearn=0.9859
F1:     手动=0.9790  sklearn=0.9790

验证通过:手动实现与 sklearn 计算结果一致。

关键说明

  • 本案例以二分类为场景,compute_metrics 函数将正类(标签为1)视为目标类。乳腺癌数据集中标签1代表良性,0代表恶性,此设定不影响指标计算逻辑。
  • 代码中同时引入 sklearn.metrics 仅用于结果比对验证,不参与核心指标计算,确保你掌握底层实现原理。
  • 若需将代码复用到其他二分类数据集,只需替换数据加载部分,并确保标签为 0/1 格式即可。