一、经验误差、测试误差、泛化误差
错误率:预测错误的样本的占比
经验误差:训练集上,样本真实输出与预测输出之间的差异
测试误差:测试集上,样本真实输出与预测输出之间的差异
泛化误差:除训练集之外,样本真实输出与预测输出之间的差异
当模型真正应用于实践中,我们是很难确定新的输出的,所以自然就不能提前求出测试误差,于是我们只能尽量将经验误差最小化。
二、评估方法(数据集的划分)
1.正常的话,我们会将数据集划分成训练集,验证集,测试集;训练集训练得到模型参数,使用验证集再次进行参数调整训练,使用测试集计算每次参数的准确率,得到最大的准确率对应的模型。
2.简化的话,就只划分训练集和测试集,训练集得到的模型参数,使用测试集计算每次参数的准确率,选择准确率最大的模型。
1.留出法(数据集很大):
通常将包含m个样本的数据集:D={(x1,y1),(x2,y2),......(xm,ym) },拆分成训练集S和测试集T,
要求:打乱;测试集数量1/5~1/3;(也可以分层采样);重复以上两步;模型参数取平均。
# 下载数据集
from sklearn.datasets import load_iris # 使用sklearn库下载鸢尾花数据集
iris = load_iris()
x,y = iris.data,iris.target # 取出数据集中的特征与标签
print(f"Dataset label:{y}")
# 数据集划分
from sklearn.model_selection import train_test_split # 留出法划分数据集函数
x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.7,random_state=23)
# train_size:设置想要训练集的大小
# random_state:设置随机数种子,会将数据集打乱后再划分
print(f"Train labels:{y_train}")
print(f"Test labels:{y_test}")
得出的结果:
Dataset label:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2]
Train labels:[2 2 2 0 1 2 2 0 2 1 1 2 1 0 2 1 0 1 0 2 1 1 2 2 1 0 0 2 0 0 2 2 1 0 1 2 1
2 2 1 0 1 2 2 1 0 1 1 1 2 1 1 2 2 2 0 2 1 0 2 2 0 1 1 2 0 0 1 0 1 1 0 2 1
1 0 2 1 2 2 1 0 0 2 2 1 0 2 1 2 1 0 0 0 2 0 0 2 0 1 0 1 0 0 1]
Test labels:[2 2 1 0 2 1 0 2 0 1 1 0 2 0 0 2 1 1 2 0 2 0 0 0 2 0 0 2 1 1 0 1 0 2 0 0 1
1 1 2 2 0 1 0 1]
分层采样的留出法划分:
from sklearn.datasets import load_digits # 使用sklearn库下载手写数字数据集
import numpy as np
digits = load_digits()
x,y = digits.data,digits.target
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.7,random_state=24,stratify=y)
# stratify: 依据标签的各个种类比列分层采样
print(f"训练集中各个标签的统计数量:{np.bincount(y_train)}")
print(f"测试集中各个标签的统计数量:{np.bincount(y_test)}")
得到的结果:
训练集中各个标签的统计数量:[124 127 124 128 127 127 127 125 122 126]
测试集中各个标签的统计数量:[54 55 53 55 54 55 54 54 52 54]
2.交叉验证法(数据集适中):
将数据集分层采样划分成k个大小相似的互斥子集,每次使用k-1个子集的并集作为训练集,余下的子集作为测试集,最终得到k的测试结果的均值。
from sklearn.datasets import load_iris # 下载数据集
from sklearn.model_selection import KFold # K折交叉验证划分函数
data = load_iris()
X = data.data
Y = data.target
kf = KFold(n_splits=5,random_state=2,shuffle=True) # 5折交叉验证,shuffle=True,开启随机打乱
# 注意kf得到的就是划分好的5个子集,每个子集的内容不变了
for train_index,test_index in kf.split(X,Y):
X_train,X_test = X[train_index],X[test_index]
Y_train,Y_test = Y[train_index],Y[test_index]
print(f"Train labels:{Y_train}")
print(f"Test labels:{Y_test}")
# 注意每一次循环,就会得到一对新的训练集和测试集
结果:
Train labels:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2]
Test labels:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2]
Train labels:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2]
Test labels:[0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2]
Train labels:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2]
Test labels:[0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2]
Train labels:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2]
Test labels:[0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2]
Train labels:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2]
Test labels:[0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2]
K折交叉验证分层数据划分法:
from sklearn.datasets import load_iris # 下载数据集
from sklearn.model_selection import StratifiedKFold # K折交叉验证划分函数
data = load_iris()
X = data.data
Y = data.target
skf = StratifiedKFold(n_splits=5,random_state=0,shuffle=True) # 5折交叉验证分层,shuffle=True,开启随机打乱
# 注意skf相比kf的区别是,划分的k个子集是分层比例得到的
for train_index,test_index in skf.split(X,Y):
X_train,X_test = X[train_index],X[test_index]
Y_train,Y_test = Y[train_index],Y[test_index]
print(f"Train labels:{Y_train}")
print(f"Test labels:{Y_test}")
# 注意每一次循环,就会得到一对新的训练集和测试集
结果:
Train labels:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2]
Test labels:[0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2]
Train labels:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2]
Test labels:[0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2]
Train labels:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2]
Test labels:[0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2]
Train labels:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2]
Test labels:[0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2]
Train labels:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2]
Test labels:[0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2]
留一法:假设数据集D包含m个样本,k = m
重复k折交叉验证数据划分法:每重复一次,划分的k个子集的内容就不一样,然后取均值
from sklearn.datasets import load_iris # 下载数据集
from sklearn.model_selection import RepeatedKFold # K折交叉验证划分函数
data = load_iris()
X = data.data
Y = data.target
rkf = RepeatedKFold(n_splits=5,n_repeats=2,random_state=None) # n_repeats 重复次数
# 注意rkf相比kf的区别是,2次重复中,每次划分的k个子集的内容不一样
for train_index,test_index in rkf.split(X,Y): # 会循环10次
X_train,X_test = X[train_index],X[test_index]
Y_train,Y_test = Y[train_index],Y[test_index]
print(f"Train labels:{Y_train}")
print(f"Test labels:{Y_test}")
# 注意每一次循环,就会得到一对新的训练集和测试集
3.自助法(数据集很小):
也称为:有放回抽样,可重复采样
import numpy as np
x = np.random.randint(-10,10,10) # 从-10到10,生成10个随机整数
# x是np.int32类型
y = (x>0).astype(int) # 转化成int类型
bootstrapping = [] # 制作随机下标
for i in range(len(x)):
bootstrapping.append(np.floor(np.random.random()*len(x)))
x_1 = []
y_1 = []
for i in range(len(x)):
x_1.append(x[int(bootstrapping[i])])
y_1.append(y[int(bootstrapping[i])])
print(x_1)
print(y_1)