别再傻傻分不清了!用Python的sklearn库5分钟搞懂准确率、精确率、召回率和F1
用Python实战解析机器学习四大核心指标:从混淆矩阵到业务决策
刚接触机器学习的开发者常会遇到这样的困惑:明明模型准确率高达90%,实际应用时却漏洞百出。上周我团队就遇到过这种情况——一个识别信用卡欺诈的模型,在测试集上表现优异,上线后却漏掉了70%的真实欺诈案例。这让我意识到,准确率只是评估模型的起点而非终点。本文将用Python带您穿透指标表象,掌握精确率、召回率和F1-score的业务决策价值。
1. 环境准备与数据加载
我们先搭建实验环境。推荐使用Anaconda创建独立Python环境,避免依赖冲突:
conda create -n metrics_demo python=3.8
conda activate metrics_demo
pip install scikit-learn pandas matplotlib seaborn
选用经典的泰坦尼克数据集而非鸢尾花,因为其更贴近真实业务场景中的二分类问题:
import pandas as pd
from sklearn.datasets import fetch_openml
# 加载数据并处理缺失值
titanic = fetch_openml('titanic', version=1, as_frame=True)
df = titanic.data.assign(survived=titanic.target)
df['age'].fillna(df['age'].median(), inplace=True)
df['embarked'].fillna(df['embarked'].mode()[0], inplace=True)
# 特征工程简化版
X = pd.get_dummies(df[['pclass', 'sex', 'age', 'sibsp', 'parch', 'fare', 'embarked']])
y = (df['survived'] == '1').astype(int)
注意:实际项目中需要更细致的特征工程,这里为突出评估指标做了简化处理
2. 混淆矩阵:指标计算的基石
理解四大指标的关键在于掌握混淆矩阵。我们用逻辑回归模型演示:
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
import seaborn as sns
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
model = LogisticRegression(max_iter=1000)
model.fit(X_train, y_train)
# 生成混淆矩阵
y_pred = model.predict(X_test)
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['Not Survived', 'Survived'],
yticklabels=['Not Survived', 'Survived'])
plt.xlabel('Predicted')
plt.ylabel('Actual')
矩阵中的四个核心元素决定了所有指标:
| 术语 | 数学符号 | 业务含义 | 泰坦尼克案例 |
|---|---|---|---|
| 真正例 | TP | 正确预测的幸存者 | 模型正确预测的幸存乘客 |
| 假正例 | FP | 错误预测的幸存者 | 实际遇难但被预测为幸存 |
| 假负例 | FN | 错误预测的遇难者 | 实际幸存但被预测为遇难 |
| 真负例 | TN | 正确预测的遇难者 | 模型正确预测的遇难乘客 |
3. 四大指标深度解析与代码实现
3.1 准确率:最直观的双刃剑
准确率计算公式为: $$ \text{accuracy} = \frac{TP + TN}{TP + FP + FN + TN} $$
在sklearn中计算:
from sklearn.metrics import accuracy_score
acc = accuracy_score(y_test, y_pred)
print(f"准确率: {acc:.2%}")
# 手动验证
manual_acc = (cm[0,0] + cm[1,1]) / cm.sum()
assert abs(acc - manual_acc) < 1e-6
业务陷阱:当数据不平衡时(如欺诈检测中正常交易占99%),即使模型总是预测"正常",准确率也能达到99%,但这样的模型毫无价值。
3.2 精确率:预测质量的严格考官
精确率关注预测为正类的准确性: $$ \text{precision} = \frac{TP}{TP + FP} $$
医疗诊断场景示例代码:
from sklearn.metrics import precision_score
precision = precision_score(y_test, y_pred)
print(f"精确率: {precision:.2%}")
# 不同阈值下的精确率变化
import numpy as np
y_proba = model.predict_proba(X_test)[:, 1]
thresholds = np.linspace(0, 1, 11)
for thresh in thresholds:
y_pred_thresh = (y_proba >= thresh).astype(int)
print(f"阈值 {thresh:.1f}: 精确率 {precision_score(y_test, y_pred_thresh):.2%}")
关键发现:提高分类阈值通常会提升精确率,但可能降低召回率
3.3 召回率:查全能力的核心指标
召回率衡量捕捉正类样本的能力: $$ \text{recall} = \frac{TP}{TP + FN}
金融风控场景实现:
```python
from sklearn.metrics import recall_score
recall = recall_score(y_test, y_pred)
print(f"召回率: {recall:.2%}")
# 绘制召回率-阈值曲线
recalls = []
for thresh in thresholds:
y_pred_thresh = (y_proba >= thresh).astype(int)
recalls.append(recall_score(y_test, y_pred_thresh))
plt.plot(thresholds, recalls)
plt.xlabel('Classification Threshold')
plt.ylabel('Recall')
3.4 F1-score:精准与查全的黄金平衡
F1-score是精确率和召回率的调和平均数: $$ F1 = 2 \times \frac{\text{precision} \times \text{recall}}{\text{precision} + \text{recall}} $$
完整评估报告生成:
from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred,
target_names=['Not Survived', 'Survived']))
典型业务场景选择策略:
- 医疗诊断:高召回率优先(宁可误诊也要查出所有病例)
- 垃圾邮件过滤:高精确率优先(避免误判重要邮件)
- 金融风控:平衡F1-score(兼顾风险管控和用户体验)
4. 高级应用与可视化分析
4.1 PR曲线与阈值优化
精确率-召回率曲线揭示模型本质特性:
from sklearn.metrics import precision_recall_curve
precisions, recalls, thresholds = precision_recall_curve(y_test, y_proba)
plt.plot(recalls, precisions)
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('PR Curve')
寻找最佳阈值的方法:
f1_scores = 2 * (precisions * recalls) / (precisions + recalls)
best_idx = np.argmax(f1_scores)
print(f"最佳阈值: {thresholds[best_idx]:.2f}, F1-score: {f1_scores[best_idx]:.2%}")
4.2 多模型指标对比
比较三种分类器的表现:
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
models = {
"Logistic Regression": LogisticRegression(max_iter=1000),
"Random Forest": RandomForestClassifier(),
"SVM": SVC(probability=True)
}
results = []
for name, model in models.items():
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
results.append({
'Model': name,
'Accuracy': accuracy_score(y_test, y_pred),
'Precision': precision_score(y_test, y_pred),
'Recall': recall_score(y_test, y_pred),
'F1': f1_score(y_test, y_pred)
})
pd.DataFrame(results).set_index('Model')
4.3 业务场景加权指标
当误分类成本不对称时,可自定义评分函数:
def business_score(y_true, y_pred, fp_cost=1, fn_cost=5):
cm = confusion_matrix(y_true, y_pred)
total_cost = cm[0,1] * fp_cost + cm[1,0] * fn_cost
return -total_cost # sklearn约定分数越高越好
from sklearn.metrics import make_scorer
business_scorer = make_scorer(business_score, greater_is_better=False)
# 用于网格搜索
from sklearn.model_selection import GridSearchCV
param_grid = {'C': [0.1, 1, 10]}
grid = GridSearchCV(LogisticRegression(), param_grid, scoring=business_scorer)
grid.fit(X_train, y_train)
更多推荐

所有评论(0)