1.经验误差与过拟合
1)经验误差与泛化误差
a.错误率:测试样本中分类错误的样本数占总样本数的比例。
E = b m × 100 % E = \frac bm ×100 \% E=mb×100%
b.精度:测试样本中分类正确的样本数占总样本数的比例。
A c c = k m × 100 % = 1 − b m × 100 % Acc = \frac km ×100 \% = 1- \frac bm ×100 \% Acc=mk×100%=1−mb×100%
错误率 + 精度 = 1
错误率与精度常用于评估分类模型的泛化能力
例:假设我们有一个水果数据集 D ;其中, D 包括了12个苹果和8个西瓜一共20个水果;我们使用数据集 D 学习得到了一个水果分类模型 M ,如图所示:
可以发现,分类模型 M 把水果分成了两部分。
其中,左边的水果分类为苹果,右边的水果分类为西瓜。
然而水果分类模型却将其中一个西瓜错分为苹果,将其中两个苹果错分为西瓜。
根据上面的计算公式,可以得到:
m = 20
b = 3
a = 17
E = b m × 100 % = 3 20 × 100 % = 15 % E = \frac bm ×100 \% = \frac {3}{20} ×100 \% = 15 \% E=mb×100%=203×100%=15%
𝐴𝑐𝑐=1−𝐸=85%
即水果分类模型的错误率是15%,精度是85%。
错误率与精度的代码实现
可以看出,水果分类模型对5、14、15号水果的分类结果是错误的。
#导入相关包
import numpy as np
#获取真实标签和预测标签 其中,0表示苹果,1表示西瓜
# 数据集的真实标签
# x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20
ground_true_label = np.array([0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1])
# 分类模型对数据集的预测标签
# x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20
classifier_pred = np.array([0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1])
#比较真实标签和预测标签
cmp = (ground_true_label == classifier_pred)
print('cmp :',cmp)
cmp = cmp.astype(np.int)
print('cmp :',cmp)
#获得样本数 m 和分类错误的样本数 b
m = len(ground_true_label)
b = m - np.sum(cmp)
#计算错误率(error rate)和精度(accuracy):
error_rate = (b/m)*100
print('error_rate=%i'%error_rate + '%')
accuracy = (1 - b/m)*100
print('accuracy=%i'%accuracy + '%')
error_rate=15%
accuracy=85%
c.误差:模型的实际预测输出与样本的真实输出之间的差异。
训练误差或经验误差:模型在训练集 D 上的误差
泛化误差: 模型在新样本的数据集 T 上的误差
2)过拟合与欠拟合
a.过拟合:训练误差和泛化误差之间的差距太大。(模型在训练集上表现很好,但在测试集上却表现很差。)
b.欠拟合:经验误差和泛化误差都很大。(模型无论是在训练集中还是在新样本上,表现都很差。)
3)原因和解决措施
a.过拟合的原因和解决措施
<1>过拟合的原因
训练数据集样本不足
训练数据中噪声干扰过大
模型过于复杂
<2>过拟合的解决措施(过拟合是无法彻底避免的,我们所能做的只是"缓解",或者说减小其风险。)
数据集增强
降低模型复杂度
Early stopping(提前终止)
降低特征的数量
Dropout (在训练过程中每次按一定的概率随机地“删除”一部分神经元)
使用正则化(在目标函数之后加上对于模型参数 W 的范数,在机器学习中一般使用 L2 正则化)
b.欠拟合的原因和解决措施
<1>欠拟合的原因:
通常是由于模型学习能力较弱,而数据复杂度较高,此时模型由于学习能力不足,无法学习到数据集中的“一般规律”。
<2>欠拟合的解决措施
增加新特征(可以考虑加入新特征来增大假设空间)
添加多项式特征(可以将线性模型通过添加二次项或者三次项使模型泛化能力更强)
减少正则化参数(模型出现了欠拟合需要减少正则化参数)
使用非线性模型(比如核SVM 、决策树、深度学习等模型)
调整模型的容量(可以适当增加模型的容量)
2.评估方法
测试集应该尽可能与训练集互斥。
我们只有一个包含m个样例的数据集D,既要训练,又要测试,一般是通过对D进行适当的处理,从中产生训练集S和测试集T。
1)留出法
直接将数据集D划分为两个互斥的集合。
例如:以二分类任务为例,假定D包含1000个样本,将其划分为S包含700个样本,T包含300个样本,用S进行训练后,如果模型在T上有90个样本分类错误,那么其错误率为(90/300)×100%=30%,相应的,精度为1-30%=70%。
在使用留出法时,需要注意:
-
要有足够的样本量,以保证训练模型的效果。
-
在划分时注意保证数据分布的一致性(如:500个样本中正例和反例的比为2:3,则在训练集和测试集中正例和反例的比也要求为2:3),只需要采用随机分层抽样即可。
-
为了减弱随机划分的影响,重复划分训练集和测试集,对得到的多次结果取平均作为最后的结果。
-
一般训练集和测试集的比例在8:2或者7:3。
import numpy as np
# 加载数据集
def load_pts():
'''
return: 返回随机生成200个点的坐标
'''
dots = 4608 # 样本数
dim = 2 #数据维度,分别表示苹果的大小和颜色
X = np.random.uniform(0, 50, (dots,dim)) #建立数据集,shape(4608,2)
# 建立样本X的类别
y = np.zeros(dots, dtype='int')
for i in range(X.shape[0]):
if X[i,0] > 18 and X[i,0] < 40 and X[i,1] > 25 and X[i,1] < 35:
y[i] = 1
return X, y
X, Y = load_pts()
# 请你补全以下代码,实现留出法
def train_test_split(X, Y, test_size, is_shuffle=True, random_state=2021):
"""
计算错误率和精度
:参数 X: 数据集样本
:参数 Y: 数据集标签
:参数 test_size: 测试集比例
:is_shuffle: 是否随机打乱数据集
:random_state: 随机种子
:返回值: train_X: 训练集样本
test_X: 训练集标签
train_Y: 测试集样本
test_Y: 测试集标签
"""
if is_shuffle is True:
shuffle_indexs=np.random.permutation(len(X))
else:
shuffle_indexs=np.arange(len(X))
test_size=int(len(X)*test_size)
test_indexs=shuffle_indexs[:test_size]
train_indexs=shuffle_indexs[test_size:]
train_X=X[train_indexs]
train_Y=Y[train_indexs]
test_X=X[test_indexs]
test_Y=Y[test_indexs]
return train_X, test_X, train_Y ,test_Y
train_X , test_X, train_Y ,test_Y = train_test_split(X, Y, 0.25, random_state=2021)
print("训练集样本train_X的shape:{}".format(train_X.shape))
print("训练集标签test_X的shape :{}".format(test_X.shape))
print("测试集样本train_Y的shape:{}".format(train_Y.shape))
print("测试集标签test_Y的shape :{}".format(test_Y.shape))
2)交叉验证法
先将数据集D划分为k个 大小相似的互斥子集
k最常用的取值是10,此时称为10折交叉验证。
留一法:若数据集 D 包含m个样本,先将数据集 D 划分为m个大小相似的子集,每个子集只有一个样本数据,则得到了交叉验证法的一个特例,留一法(Leave-One-Out,简称LOO)。
# 导入包
from sklearn.model_selection import KFold
import numpy as np
# 生成数据集,随机生成40个点
data = np.random.randn(40,2)
# 交叉验证法
kf = KFold(n_splits = 10,shuffle = False,random_state = None)
for train, test in kf.split(data):
print(train)
print(test,'\n')
3)自助法
有放回抽样,给定包含m个样本的数据集 D ,我们对它进行采样产生数据集 D’ :
- 每次随机从 D 中挑选一个样本;
- 将该样本拷贝放入 D’,然后再将该样本放回初始数据集 D 中;
- 重复执行m次该过程;
- 最后得到包含m个样本数据集 D’。
初始数据集D中有一部分样本会在数据集 D’ 中多次出现,也有一部分样本不会在数据集 D’ 中出现。
样本在m次采样中始终不被采到的概率是:
对m取极限得到:
通过上式可知,初始数据集 D 中约有36.8%的样本未出现在采样数据集 D’ 中。
于是我们可以将 D’ 用作训练集,实际评估的模型与期望评估的模型都使用 m 个训练样本,我们仍有数据总量约1/3的,没在训练集中出现的样本作为测试集用于测试这样的测试结果,亦被称为”包外估计“(out-of-bag estimate)。
自助法产生数据集改变了初始数据集的分布会引入估计偏差,数据集D分为D1,D2,D3,D4数据集,假设知道自助采样的数据集结果,比较自助法采样产生的数据集分布和初始数据集的分布。
# 导入包
import numpy as np
#任意设置一个数据集
X = [1,4,3,23,4,6,7,8,9,45,67,89,34,54,76,98,43,52]
#通过产生的随机数获得抽取样本的序号
bootstrapping = []
for i in range(len(X)):
bootstrapping.append(np.random.randint(0,len(X),(1)))
#通过序号获得原始数据集中的数据
D_1 = []
for i in range(len(X)):
D_1.append(X[int(bootstrapping[i])])
print(D_1)
4)评估方法比较
小样本数据集:建议采用自助法
大一点样本数据集:建议采用十折交叉验证法
超大样本数据集:建议采用留出法
5)调参与最终模型
机器学习算法工程师通常被称为“调参侠”,由此可见调参在机器学习应用中有举足轻重的地位。
在不少应用任务中,参数调的好不好往往对最终模型性能有关键性影响。
a.调参
大多数学习算法都有些参数(parameter) 需要设定,参数配置不同,学得模型的性能往往有显著差别。因此,在进行模型评估与选择时,除了要对适用学习算法进行选择,还需对算法参数进行设定,这就是通常所说的"参数调节"或 简称"调参" (parameter tuning)。
一般来说:
对每种参数配置都训练出模型,然后把对应最好模型的参数作为结果。
但需注意:
学习算法的很多参数是在实数范围内取值,因此,对每种参数配置都训练出模型来是不可行的。现实中常用的做法,是对每个参数选定一个范围和变化步长,例如在 [0 0.2] 范围内以 0.05 为步长,则实际要评估的候选参数值有5个,最终是从这5个候选值中产生选定值。
显然,这样选定的参数值往往不是"最佳"值,但这是在计算开销和性能估计之间进行折中的结果,通过这个折中,学习过程才变得可行。
调参的复杂性:
假定算法有3个参数,每个参数仅考虑5个候选值,这样对每一组训练/测试集就有 5^3 = 125 个模型需考察;很多强大的学习算法有大量参数需设定,这将导致极大的调参工程量。
b.最终模型:
用于对新数据进行预测的机器学习模型。
也就是说,给出新输入数据的例子,然后使用该模型预测输出的值。这可能是一个分类(分配标签)或回归(估实际值)模型。
例如,不管是判断猫还是狗的照片,还是明天的估计销售数量;机器学习项目的目标是获得最佳的最终模型,其中“最佳”由以下因素决定:
数据:可用的历史数据。
时间:在项目上花费的时间。
程序:数据准备步骤,一个或多个算法,以及算法配置的选择。
在整个项目中,收集数据,花费大量时间;要使用数据准备程序,要使用的算法以及如何对其进行配置。
最终的模型是这个过程的巅峰之作,最后你会发现实际上就是要做预测。
c.训练集VS验证集VS测试集:
- 训练集(train set) —— 用于模型拟合的数据样本。
- 验证集(validation set)—— 是模型训练过程中单独留出的样本集,它可以用于调整模型的超参数和用于对模型的能力进行初步评估。 通常用来在模型迭代训练时,用以验证当前模型泛化能力(准确率,召回率等),以决定是否停止继续训练。
- 测试集 —— 用来评估模最终模型的泛化能力。但不能作为调参、选择特征等算法相关的选择的依据。
举栗子:
(1)训练集:学生的课本;学生根据课本里的内容来掌握知识
(2)验证集:作业;通过作业可以知道不同学生学习情况、进步的速度快慢
(3)测试集:考试;考的题是平常都没有见过,考察学生举一反三的能力
3.性能度量
1)性能度量的概念
对学习器的泛化性能进行评估,不仅需要有效可行的实验估计方法,还需要有衡量模型泛化能力的评价标准,这就是性能度量。
性能度量反映了任务需求,在对比不同模型的能力时,使用不同的性能度量往往会导致不同的评判结果。
这意味着模型的"好坏"是相对的,什么样的模型是好的? 这不仅取决于算法和数据,还决定于任务需求。
2)评估指数
a.均方误差MSE
回归任务最常用的性能度量是"均方误差"。
M S E = E ( f ; D ) = 1 m ∑ i = 1 m ( f ( x i ) − y i ) 2 MSE = E(f;D) = \frac 1m \sum_{i=1}^m (f(x_i)-y_i)^2 MSE=E(f;D)=m1i=1∑m(f(xi)−yi)2
b.错误率与精度
错误率与精度是分类任务常用的性能度量
错误率:
E ( f ; D ) = 1 m ∑ i = 1 m P ( f ( x i ) ≠ y i ) E(f;D) = \frac 1m \sum_{i=1}^m P(f(x_i) \ne y_i) E(f;D)=m1i=1∑mP(f(xi)=yi)
精度:
a c c ( f ; D ) = 1 − E ( f ; D ) = 1 m ∑ i = 1 m P ( f ( x i ) = y i ) acc(f;D) = 1-E(f;D) =\frac 1m \sum_{i=1}^m P(f(x_i)