在机器学习分类任务中,Accuracy(准确率)是最直观的评估指标,计算公式简单明了:
code复制Accuracy = (TP + TN) / (TP + TN + FP + FN)
但我在实际项目中多次发现,当数据分布不平衡时,这个指标会产生严重误导。去年处理过一个医疗诊断案例:在癌症筛查数据集中,阴性样本占比98%,阳性仅2%。即使模型将所有样本预测为阴性,Accuracy也能达到98%,但这显然是个完全无效的模型!
场景1:极端类别不平衡
场景2:不同误分类代价悬殊
关键经验:当数据中多数类占比超过80%,或不同错误类型代价差异显著时,Accuracy就会失去参考价值。
F1-Score是Precision和Recall的调和平均数,其计算公式为:
code复制F1 = 2 * (Precision * Recall) / (Precision + Recall)
我在Python中通常这样实现:
python复制from sklearn.metrics import f1_score
# 二分类场景
y_true = [0, 1, 1, 0, 1]
y_pred = [0, 1, 0, 0, 1]
print(f1_score(y_true, y_pred)) # 输出0.6667
# 多分类场景
print(f1_score(y_true, y_pred, average='macro')) # 宏平均
print(f1_score(y_true, y_pred, average='micro')) # 微平均
print(f1_score(y_true, y_pred, average='weighted')) # 加权平均
我在实际项目中发现,当小类别具有特殊重要性时(如金融风控中的欺诈交易),宏平均往往能更好反映模型在关键类别上的表现。
F1-Score对分类阈值非常敏感。我常用的阈值搜索策略:
python复制from sklearn.metrics import precision_recall_curve
probs = model.predict_proba(X_test)[:, 1]
precisions, recalls, thresholds = precision_recall_curve(y_test, probs)
# 计算每个阈值对应的F1
f1_scores = 2 * (precisions * recalls) / (precisions + recalls + 1e-7)
optimal_idx = np.argmax(f1_scores)
optimal_threshold = thresholds[optimal_idx]
避坑提示:记得在分母添加极小值(如1e-7)避免除零错误,这在极端不平衡数据中经常发生。
通过class_weight参数调整类别权重:
python复制# 逻辑回归中的类别加权
model = LogisticRegression(class_weight={0:1, 1:10})
# 随机森林中的平衡模式
model = RandomForestClassifier(class_weight='balanced')
我的经验法则是:将少数类的权重设为多数类样本量的倒数。例如100:1的不平衡数据,少数类权重设为100。
我常用的完整评估流程:
python复制from sklearn.metrics import classification_report
print(classification_report(y_true, y_pred, target_names=['class0', 'class1']))
输出包含:
在最近的一个客户流失预测项目中,我们最终选择MCC作为主要指标,因为它在极度不平衡(95:5)时仍能保持稳定性。
某团队在文本分类中通过以下方式"提升"F1:
正确做法:
在信用卡欺诈检测中,单纯优化F1可能导致:
解决方案:
总成本 = FP*100 + FN*5000python复制# 交互式阈值分析
import plotly.express as px
df = pd.DataFrame({'Threshold': thresholds, 'F1': f1_scores})
fig = px.line(df, x='Threshold', y='F1', title='F1-Score by Threshold')
fig.show()
# 类别对比分析
from sklearn.metrics import ConfusionMatrixDisplay
ConfusionMatrixDisplay.from_predictions(y_true, y_pred)
我在生产环境实现的监控流程:
这个系统曾帮助我们及时发现了一个因数据采集设备故障导致的指标下降问题。
在同一个电信客户流失数据集上(流失率15%),不同算法的F1表现:
| 算法 | 宏F1 | 加权F1 | 计算时间 |
|---|---|---|---|
| 逻辑回归 | 0.62 | 0.85 | 1.2s |
| 随机森林 | 0.68 | 0.88 | 8.7s |
| XGBoost | 0.71 | 0.89 | 4.5s |
| LightGBM | 0.73 | 0.90 | 3.1s |
经验观察:集成方法通常在小样本类别上表现更好,但计算成本更高。对于实时性要求高的场景,可以接受轻微的性能损失选择更轻量级的模型。
通过增量学习观察F1变化规律:
python复制learning_curve = []
for n in [100, 500, 1000, 5000]:
model.fit(X_train[:n], y_train[:n])
y_pred = model.predict(X_test)
learning_curve.append(f1_score(y_test, y_pred))
plt.plot([100,500,1000,5000], learning_curve)
典型发现:
在肺部CT影像分类项目中(肺炎检测),我们采用:
这套方案将临床可用性提高了40%,同时减少了不必要的复查。
信用卡欺诈检测的特殊考量:
python复制def weighted_f1(y_true, y_pred, amount):
fn_mask = (y_true==1)&(y_pred==0)
fp_mask = (y_true==0)&(y_pred==1)
tp_mask = (y_true==1)&(y_pred==1)
fn_cost = np.sum(amount[fn_mask])
fp_cost = len(fp_mask) * 100 # 假设每笔FP固定成本
precision = np.sum(amount[tp_mask]) / (np.sum(amount[y_pred==1]) + 1e-7)
recall = np.sum(amount[tp_mask]) / (np.sum(amount[y_true==1]) + 1e-7)
return 2 * (precision * recall) / (precision + recall + 1e-7)
这个定制指标帮助我们更精准地平衡风险和成本。