在上一节课中,我们学习了如何系统地评估和诊断机器学习模型。但在实际应用中,还有许多重要的实践技巧需要掌握。如何分析模型的错误?如何处理类别不平衡的数据?如何决定是否需要获取更多数据?
所以这部分我们将深入探讨这些实践中的关键问题。我们会学习如何进行误差分析,如何为不同应用场景选择合适的评估指标,如何高效地改进系统性能。这些经验和技巧来自于大量的实际项目,能够帮助你避免常见的陷阱,更快地构建出有效的机器学习系统。
想象你正在构建一个垃圾邮件分类器。你的模型在验证集上达到了95%的准确率,但还不够好。你有很多可以尝试的方向:
面对这么多选择,如何决定优先级?盲目尝试可能会浪费几周甚至几个月的时间。
步骤1:快速实现一个简单的系统
不要追求完美。快速实现一个端到端的系统,即使很简陋。这能让你:
对于垃圾邮件分类,可以从最简单的方法开始:统计邮件中出现的常见垃圾邮件词汇(如“discount”, “free”, “click here”等),用朴素贝叶斯或逻辑回归分类。可能只需要一两天就能实现。
步骤2:绘制学习曲线
手动检查验证集上的错误案例。对于垃圾邮件分类器,可能发现:
这个分析告诉你:如果能更好地识别药品广告,性能可以提升40%(12/30)。这就是你应该优先解决的问题。
步骤3:针对性改进
基于误差分析的洞察,有针对性地改进系统。每次改进后,重新评估,看是否真的带来了提升。
误差分析是指系统地检查模型犯错的案例,找出共同的模式和改进方向。
1. 收集错误样本
从验证集中选出所有被错误分类的样本。样本数量不需要太多,100-500个通常就够了(如果错误样本很少,就全部分析)。
2. 手动检查和分类
对每个错误样本,记录:
可以建一个简单的表格:
3. 统计和优先级
统计每种错误类型的占比。这能帮助你决定应该优先解决哪个问题。
|def errorAnalysis(X_val, y_val, predictions): """ 误差分析:找出所有错误样本 """ errors = np.where(predictions != y_val)[0] print(f"验证集错误数量: {len(errors)}") print(f"错误率: {len(errors) / len(y_val) * 100:.2f}%") # 随机抽取一些错误样本进行分析
4. 量化改进的潜在影响
对于每个发现的问题,估算解决它能带来多大的提升。比如:
这样你就知道应该先解决药品广告问题。
5. 迭代
实施改进,重新评估,再做误差分析。可能会发现新的问题类型,或者原来的问题已经改善但其他问题变得更突出。

在很多实际应用中,不同类别的重要性不同,或者样本数量严重不平衡。这时候简单的准确率不是好的评估指标。
例子:癌症诊断
假设我们要诊断一种罕见癌症,只有0.5%的患者真正患病。一个简单的分类器总是预测“没有癌症”,准确率是99.5%!但这个分类器完全没用——它一个癌症患者都没识别出来。
对于这种情况,我们需要更细致的评估指标。
混淆矩阵(Confusion Matrix)
精确率(Precision)
在所有预测为正类的样本中,真正是正类的比例:
精确率回答:“当我们说某人有癌症时,有多大把握是对的?”
召回率(Recall,也叫敏感度Sensitivity)
在所有实际为正类的样本中,被正确识别的比例:
召回率回答:“在所有真正有癌症的人中,我们识别出了多少?”
|from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score # 计算混淆矩阵 cm = confusion_matrix(y_true, y_pred) print("混淆矩阵:") print(cm) # 计算指标 precision = precision_score(y_true, y_pred) recall = recall_score(y_true, y_pred) f1 = f1_score(y_true, y_pred) print(f"精确率: {precision:.3f}") print(
F1分数(F1 Score)
精确率和召回率的调和平均:
F1分数在精确率和召回率之间取得平衡,是评估不平衡数据集的好指标。
对于很多分类器(如逻辑回归),我们可以通过调整决策阈值来权衡精确率和召回率。
默认情况下,阈值是0.5:如果 预测为正类。但我们可以调整这个阈值:
提高阈值(如0.7):
降低阈值(如0.3):
|from sklearn.metrics import precision_recall_curve import matplotlib.pyplot as plt # 计算不同阈值下的精确率和召回率 precisions, recalls, thresholds = precision_recall_curve(y_true, probabilities) # 画出PR曲线 plt.plot(recalls, precisions) plt.xlabel('召回率') plt.ylabel('精确率') plt.title('精确率-召回率曲线') plt.show() # 选择合适的阈值 # 例如,想要至少90%的精确率 threshold_90_precision = thresholds[np.where(precisions >= 0.9)[0][

如何选择?
这取决于应用场景的代价:
在评估模型时,不要只看一个指标。对于不平衡的数据,同时考虑精确率、召回率和F1分数。理解你的应用场景中哪种错误更严重,相应地调整阈值或优化目标。
“数据是新的石油”——这句话在机器学习领域尤其正确。很多时候,性能的提升不是来自更复杂的算法,而是来自更多更好的数据。
什么时候更多数据有帮助?
不是所有情况下增加数据都有用。回忆学习曲线:
经验法则:如果一个人类专家查看特征 ,能够自信地预测 ,那么更多数据可能有帮助。如果特征本身就不包含足够的信息,再多数据也无济于事。
获取数据的策略:
1. 人工数据合成
对于某些问题,我们可以人工生成训练数据。例如:
|from scipy import ndimage def augmentImage(image): """数据增强:生成图片的变体""" augmented = [] # 原始图片 augmented.append(image) # 旋转 for angle in [-15, 15]: rotated = ndimage.rotate(image, angle, reshape=False) augmented.append(rotated) # 缩放 for
2. 众包标注
利用平台(如Amazon Mechanical Turk)让人工标注数据。注意:
3. 主动学习
不是随机收集数据,而是让模型告诉我们哪些样本最有价值:
这样可以用更少的标注达到更好的效果。
数据质量 vs 数量
记住:质量往往比数量更重要。100个高质量的样本可能比1000个噪声样本更有用。
数据清洗的重要性:
有时候,花一天时间清洗数据,比花一周时间调整算法带来的提升更大。
在下一节课中,我们将学习支持向量机(SVM)——一个强大的分类算法。SVM在很多问题上表现出色,特别是在样本数量不是特别大的时候。我们会看到,SVM引入了新的思想——最大间隔和核函数。
问题诊断和解决方案:根据以下情况,诊断问题并提出解决方案。
你训练了一个模型,得到:
这是什么问题?应该如何解决?
答案:
诊断:高方差(过拟合)
判断依据:
解决方案(按优先级):
获取更多训练数据 ✓ 最有效
减少特征数量 ✓
增加正则化参数λ ✓
使用更简单的模型 ✓
不应该做的:
Python诊断代码:
|def diagnose_model(train_error, val_error): gap = val_error - train_error if train_error > 0.15: # 高偏差 if gap < 0.05: return "欠拟合(高偏差)" else:
学习曲线分析:分析以下学习曲线,判断问题类型。
随着训练样本数量增加:
这是什么问题?解决方案是什么?
答案:
诊断:轻度高方差(过拟合),可能混合轻度高偏差
学习曲线特征分析:
训练误差上升(10% → 18%)
验证误差下降(60% → 20%)
曲线趋于平缓
判断:
解决方案:
如果目标误差可接受(如15%):
如果目标误差更低(如5%):
典型学习曲线模式:
|高方差(过拟合): 训练误差:很低且平 验证误差:高且有大gap 解决:更多数据有帮助 高偏差(欠拟合): 训练误差:高且平 验证误差:高且gap小 解决:更多数据帮助不大,需要更复杂模型 理想状态: 两条曲线都低且接近 差距很小