1.过拟合与欠拟合
过拟合:指模型很好的拟合训练样本,但对新数据的预测准确性很差
欠拟合:模型不能很好的拟合训练样本,且对新数据的预测准确性也不好
示例演示:
import numpy as np
import matplotlib.pyplot as plt
import sklearn
%matplotlib inline
n_dots = 20
x = np.linspace(0,1,n_dots)#区间0-1之间创建20个间隔均匀的数字
y = np.sqrt(x) + 0.2*np.random.rand(n_dots) - 0.1
def plot_polynomial_fit(x, y, order):
p = np.poly1d(np.polyfit(x, y, order))
#画出拟合出来的多项式所表达的曲线及原始点
t = np.linspace(0, 1, 200)
plt.plot(x, y, 'ro', t, p(t), '-', t, np.sqrt(t), 'r--')
return p
plt.figure(figsize = (18,4),dpi = 200)
titles = ['underfitting', 'fitting' , 'overfitting']
models = [None,None,None]
for index,order in enumerate([1,3,10]):
plt.subplot(1,3,index + 1)
models[index] = plot_polynomial_fit(x, y, order )
plt.title(titles[index], fontsize = 20)
运行结果如下所示:
2.成本函数
成本是衡量模型与训练样本符合程度的指标,简而言之,成本是针对所有的训练样本,模型拟合出来的值与训练样本的真实值的误差平均值,而成本函数就是成本与模型参数的函数关系.模型训练的过程,就是找出合适的模型参数,使得成本函数的值最小,成本函数记为,其中
表示模型参数.
如下就是模型的成本函数公式
其中m是训练样本个数, 就是模型对应的每个样本的预测值,
是每个样本的真实值,上述公式实际就是线性回归算法的成本函数的简化表达.事实上,针对一个数据集,我们可以选择很多个模型来拟合数据,一旦选定了某个模型,就需要从这个模型的无穷多个参数里找出一个最优的参数,使得成本函数的值最小.训练样本成本最小的模型不一定最好,因为可能存在过拟合的情况.
3.模型准确性
测试数据集成本,是评估模型准确性的最直观的指标,
值越小说明模型预测出来的值与实际值差异越小,对新数据的预测准确性就越好.需要注意的是,用来测试模型准确性的数据集,必须是模型“没见过”的数据.
那么,我们要怎么计算测试数据集的误差呢?简单地说,就是用测试数据集和训练出来的模型参数代入相应的成本函数里,计算测试数据集的成本。
针对前面提到过的线性回归算法,可以使用下面的公式计算测试数据集的误差,其中m是测试数据集的个数:
3.1模型性能的不同表述方式
(1).在scikit-learn里,不使用成本函数来表达模型的性能,而是用分数来表达,这个分数总是在[0,1]之间,数值越大说明模型的准确性越好.当模型训练完成后,调用模型的score[X_test,y_test]即可算出模型的分数值,其中X_test和y_test是测试数据集样本.
(2).模型分数(准确性)与成本成反比。即分数越大,准确性越高,误差越小,成本越低;反之,分数越小,准确性越低,误差越大,成本越高
3.2交叉验证数据集
更科学的方法是数据集分成3份,分别是训练数据集、交叉验证数据集和测试数据集,推荐比例为6:2:2;
在模型选择时,可以使用训练数据集来训练算法参数,用交叉验证数据集来验证参数,选择交叉验证数据集的成本最小的多项式来作为数据拟合模型,最后再用测试数据集来测试选择出来的模型针对测试数据集的准确性.这样就保证了选择的模型是没有见过测试数据的目的.
4.学习曲线
把和
作为纵坐标,训练数据m作为横坐标,画出与训练数据m到的大小关系,这就是学习曲线。通过学习曲线,可以直观地观察到模型的准确性与训练数据集大小的关系.
如果数据集的大小为m,则通过下面的流程即可画出学习曲线:
- 把数据集分成训练数据集和交叉验证数据集;
- 提取训练数据集的20%作为训练样本,训练出模型参数;
- 使用交叉验证数据集来计算训练出来的模型的准确性;
- 以训练数据集的准确性,交叉验证的准确性作为纵坐标想,训练数据集个数作为横坐标,在坐标轴上画出上述步骤计算出来的模型准确性;
- 训练数据集增加10%,跳到步骤3继续执行,直到训练数据集大小为100%为止。
学习曲线要表达的是,当训练数据集增加时,模型对训练数据集拟合的准确性以及对交叉验证数据集预测的准确性的变化规律
4.1画学习曲线示例:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
n_dots = 200
X = np.linspace(0, 1, n_dots)
y = np.sqrt(X) + 0.2*np.random.rand(n_dots) - 0.1;
X = X.reshape(-1, 1)
y = y.reshape(-1, 1)
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
def polynomial_model(degree=1):
polynomial_features = PolynomialFeatures(degree=degree,
include_bias=False)
linear_regression = LinearRegression()
pipeline = Pipeline([("polynomial_features", polynomial_features),
("linear_regression", linear_regression)])
return pipeline
from sklearn.model_selection import learning_curve
from sklearn.model_selection import ShuffleSplit
def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None,
n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5)):
plt.title(title)
if ylim is not None:
plt.ylim(*ylim)
plt.xlabel("Training examples")
plt.ylabel("Score")
train_sizes, train_scores, test_scores = learning_curve(
estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes)
train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)
plt.grid()
plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
train_scores_mean + train_scores_std, alpha=0.1,
color="r")
plt.fill_between(train_sizes, test_scores_mean - test_scores_std,
test_scores_mean + test_scores_std, alpha=0.1, color="g")
plt.plot(train_sizes, train_scores_mean, 'o--', color="r",
label="Training score")
plt.plot(train_sizes, test_scores_mean, 'o-', color="g",
label="Cross-validation score")
plt.legend(loc="best")
return plt
# 为了让学习曲线更平滑,交叉验证数据集的得分计算 10 次,每次都重新选中 20% 的数据计算一遍
cv = ShuffleSplit(n_splits=10, test_size=0.2, random_state=0)
titles = ['Learning Curves (Under Fitting)',
'Learning Curves',
'Learning Curves (Over Fitting)']
degrees = [1, 3, 10]
plt.figure(figsize=(18, 4), dpi=200)
for i in range(len(degrees)):
plt.subplot(1, 3, i + 1)
plot_learning_curve(polynomial_model(degrees[i]), titles[i], X, y, ylim=(0.75, 1.01), cv=cv)
plt.show()
运行结果如上
4.2过拟合和欠拟合的特征
过拟合:模型对训练数据集的准确性比较高,其成本比较低,对交叉验证数据集的准确性比较低,其成本
比较高。
欠拟合:模型对训练数据集的准确性比较低,其成本比较高,对交叉验证数据集的准确性也比较低,其成本
也比较高。
一个好的机器学习算法应该是对训练数据集准确性高、成本低,即比较准确地拟合数据,同时对交叉验证数据集准确性高、成本低、误差小,即对未知数具有良好的预测性
5.算法模型性能优化
1、过拟合
- 获取更多的训练数据:从学习曲线的规律来看,更多的数据有助于改善过拟合问题。
- 减少输入的特征数量:比如,针对书写识别系统,原来使用200x200的图片,总共40000个特征。优化后,我们可以把图片等比例缩小为10x10的图片,总共100个特征。这样可以大大减少模型的计算量,同时也缩减模型的复杂度,改善过拟合问题。
2、欠拟合,说明模型太简单,需要增加模型的复杂度。
- 增加有价值的特征:重新解读并理解训练数据。比如针对一个房产价格预测的机器学习任务,原来只根据房子面积来预测价格,结果模型出现了欠拟合。优化后,我们增加其他的特征,比如房子的朝向、户型、年代、房子旁边的学校的质量等。
- 增加多项式特征
6.查准率和召回率
1、实际上非常简单,精确率是针对我们预测结果而言的,它表示的是预测为正的样本中有多少是真正的正样本。那么预测为正就有两种可能了,一种就是把正类预测为正类(TP),另一种就是把负类预测为正类(FP),也就是
而召回率是针对我们原来的样本而言的,它表示的是样本中的正例有多少被预测正确了。那也有两种可能,一种是把原来的正类预测成正类(TP),另一种就是把原来的正类预测为负类(FN)。
通常希望检索结果Precision越高越好,同时Recall也越高越好,但事实上这两者在某些情况下有矛盾的。比如极端情况下,我们只搜索出了一个结果,且是准确的,那么Precision就是100%,但是Recall就很低;而如果我们把所有结果都返回,那么比如Recall是100%,但是Precision就会很低。因此在不同的场合中需要自己判断希望Precision比较高或是Recall比较高。如果是做实验研究,可以绘制Precision-Recall曲线来帮助分析
7.F1Score
如果有多个算法,彼此之间的查准率和召回率是不一样的,那么应该怎么确定哪个算法更好呢?
这里就涉及到了查准率,公式为:
P为查准率,R为召回率。这样就可以用一个数值直接判断哪个算法性能更好。
通常我们选择在验证集上,会选择F1 Score 数值最大的那个模型假设.