应用机器学习的建议

机器学习应用的建议

《数学之美》这本书中有一句让我印象深刻的话:“许多失败并不是因为人不优秀,而是做事情的方法不对,一开始追求大而全的解决方案,之后长时间不能完成。最后不了了之”。在这一周的学习课程中,Andrew Ng同样给我们传达了这样的理念:”研究机器学习的东西,或者构造机器学习应用程序,最好的实践方法不是建立一个非常复杂的系统,拥有多么复杂的变量;而是构建一个简单的算法,这样你可以很快地实现它,然后再在这个基础上决定下一步怎么完善

决定下一步

  • 获得更多训练实例
  • 减少特征数量
  • 获得更多特征
  • 增加多项式特征
  • 减少正则化程度$\lambda$
  • 增加正则化程度$\lambda$

评估假设(Evaluating a Hypothesis)

过拟合问题

将数据分为训练集和测试集。
两种方法计算误差:

  • 线性回归模型:计算代价函数$J$
  • 逻辑回归模型:计算代价函数$J$或者误分类比率最后对计算结果求平均

模型选择和交叉验证集(Model Selection and Train Validation Test Sets)

交叉验证集

适应训练数据集不代表能推广到一般情况,使用较差验证集来帮助选择模型:使用60%的数据作为训练集,使用20%数据作为交叉验证集,使用20%的数据作为测试集。

模型选择方法

  • 使用训练集训练出10个模型
  • 分别计算得出交叉验证误差
  • 选取代价函数最小的模型
  • 用步骤3选出的模型对测试集计算得出误差(代价函数的值)

诊断偏差和方差

算法不理想的两种情况

  • 偏差较大: 欠拟合
  • 方差较大:过拟合

将训练集和交叉验证集的代价函数误差与多项式次数绘制在同一张图上进行分析

  • 训练集误差和交叉验证集误差近似时:高偏差/欠拟合
  • 交叉验证集误差远大于训练集误差时:高方差/过拟合

正则化和偏差/方差

选择$\lambda$的方法

  • 使用训练集训练出12个不同程度正则化的模型;
  • 用12个模型分别对交叉验证集计算出交叉验证误差;
  • 选择交叉验证误差最小的模型;
  • 运用步骤3中选出的模型对测试集计算得出推广误差,我们也可以同时将训练集和交叉验证集模型的代价函数误差与λ的值绘制在一张图表上。

  • 当λ较小时,训练集误差较小(过拟合)而交叉验证集误差较大

  • 随着λ的增加,训练集误差不断增加(欠拟合),而交叉验证集误差则是先减小后增加

学习曲线(Learning Curves)

合理检验(sanity check)

学习曲线是将训练集误差和交叉验证集误差作为训练集实例数量(m)的函数绘制的图表。

如何利用学习曲线识别高偏差/欠拟合:

作为例子,我们尝试用一条直线来适应下面的数据,可以看出,无论训练集有多么大误差都不会有太大改观:

也就是说在高偏差/欠拟合的情况下,增加数据到训练集不一定能有帮助。

如何利用学习曲线识别高方差/过拟合

假设我们使用一个非常高次的多项式模型,并且正则化非常小,可以看出,当交叉验证集误差远大于训练集误差时,往训练集增加更多数据可以提高模型的效果。

也就是说在高方差/过拟合的情况下,增加更多数据到训练集可能可以提高算法效果。

决定下一步做什么

六种可选步骤

  • 获得更多的训练实例——解决高方差(high variance)
  • 尝试减少特征的数量——解决高方差(high variance)
  • 尝试获得更多的特征——解决高偏差(high bias)
  • 尝试增加多项式特征——解决高偏差(high bias)
  • 尝试减少正则化程度λ——解决高偏差(high bias)
  • 尝试增大正则化程度λ——解决高方差(high variance)

神经网络的方差和偏差

使用较小的神经网络,类似于参数较少的情况,容易导致高偏差和欠拟合,但计算代价较小。使用较大的神经网络,类似于参数较多的情况,容易导致高方差和过拟合,虽然计算代价比较大,但是可以通过正则化手段来调整而更加适应数据。
对于神经网络中的隐藏层的层数的选择,通常从一层开始逐渐增加层数,为了更好地作选择,可以把数据分为训练集、交叉验证集和测试集,针对不同隐藏层层数的神经网络训练神经网络, 然后选择交叉验证集代价最小的神经网络。

机器学习系统的设计

垃圾邮件分类器算法

选择并表达特征向量x

  • 收集更多的数据,让我们有更多的垃圾邮件和非垃圾邮件的样本
  • 基于邮件的路由信息开发一系列复杂的特征
  • 基于邮件的正文信息开发一系列复杂的特征,包括考虑截词的处理
  • 为探测刻意的拼写错误(把watch 写成w4tch)开发复杂的算法

误差分析

  • 从一个简单的能快速实现的算法开始,实现该算法并用交叉验证集数据测试这个算法;
  • 绘制学习曲线,决定是增加更多数据,或者添加更多特征,还是其他选择;
  • 进行误差分析:人工检查交叉验证集中我们算法中产生预测误差的实例,看看这些实例是否有某种系统化的趋势。

误差分析并不总能帮助我们判断应该采取怎样的行动。有时我们需要尝试不同的模型,然后进行比较,在模型比较时,用数值来判断哪一个模型更好更有效,通常我们是看交叉验证集的误差。

总结一下,当研究一个新的机器学习问题时,推荐实现一个较为简单快速、即便不是那么完美的算法。

类偏斜的误差度量

偏斜类(skewed classes)

类偏斜情况表现为我们的训练集中有非常多的同一种类的实例,只有很少或没有其他类的实例。

查准率(perecision)和召回率(recall)

  • 正确肯定(True Positive,TP,真阳性):预测为真,实际为真;
  • 正确否定(True Negative,TN,真阴性):预测为假,实际为假;
  • 错误肯定(False Positive,FP,假阳性):预测为真,实际为假;
  • 错误否定(False Negative,FN,假阴性):预测为假,实际为真。

查准率:$\frac{TP}{TP+FP}$
召回率:$\frac{TP}{TP+FN}$

权衡查准率与召回率

以肿瘤预测为例,如果我们希望只在非常确信的情况下预测为真(肿瘤为恶性),即我们希望更高的查准率,我们可以使用比0.5 更大的阀值,如0.7,0.9。这样做我们会减少错误预测病人为恶性肿瘤的情况,同时却会增加未能成功预测肿瘤为恶性的情况。
如果我们希望提高召回率,尽可能地让所有有可能是恶性肿瘤的病人都得到进一步地检查、诊断,我们可以使用比0.5 更小的阀值,如0.3。

选择阈值的方法

$F_1Score:2\frac{PR}{P+R}$
选择使$F_1$最高的阈值

机器学习的数据

取得成功的人不是拥有最好算法的人,而是拥有最多数据的人

有用的训练集

  • 在我们的机器学习问题中,特征值x 包含了足够的信息,这些信息可以帮助我们用来准确地预测 y
  • 有一个高性能的学习算法,我们希望它不要有高的偏差和方差。

作业回顾(Regularized Linear Regression and Bias-Variance)

优化线性回归

代价函数(linearRegCostFunction)

1
2
3
J = 1 / (2*m) * sum((X*theta-y).^2) + lambda / (2*m) * sum(theta(2:end).^2);
grad = (1 / m) * X'*(X*theta-y) + (lambda / m) * theta;
grad(1) = grad(1) - (lambda) / m * theta(1);

学习曲线(learning curve)

1
2
3
4
5
for i = 1:m, %实例逐渐增加
[theta] = trainLinearReg(X(1:i,:), y(1:i), lambda); %训练参数
error_train(i) = linearRegCostFunction(X(1:i,:),y(1:i),theta,0); %将训练结果用于求训练集误差(不带正则化)
error_val(i) = linearRegCostFunction(Xval,yval,theta,0); %将训练结果用于求交叉验证集误差(不带正则化)
end

多项式回归(Polynomial regression)

X_poly = zeros(numel(X), p);
for i=1:p,
    X_poly(:,i) = X.^i;
end

使用交叉验证集选择$\lambda$

1
2
3
4
5
for i =1:size(lambda_vec),
[theta] = trainLinearReg(X,y,lambda_vec(i)); % 训练参数
[error_train(i),gradt] = linearRegCostFunction(X,y,theta,0); % 将训练结果用于求训练集误差(不带正则化)
[error_val(i),gradcv] = linearRegCostFunction(Xval,yval,theta,0); %将训练结果用于求交叉验证集误差(不带正则化)
end

随机选择实例来画学习曲线

1
2
3
4
5
6
7
8
9
10
for i = 1:m,
for j = 1:50, %每个实例数量随机选取50次来训练参数
data = randperm(m,i);
[theta] = trainLinearReg(X(data,:),y(data),0.01);
error_train_r(i) = error_train_r(i) + linearRegCostFunction(X(data,:),y(data),theta,0);
error_val_r(i) = error_val_r(i) + linearRegCostFunction(Xval,yval,theta,0);
end
error_train_r(i) = error_train_r(i) / 50; %求平均值
error_val_r(i) = error_val_r(i) / 50;
end