交叉验证
概述Holdout 交叉验证K-Fold 交叉验证Leave-P-Out 交叉验证总结
概述
交叉验证是在机器学习建立模型和验证模型参数时常用的办法。
顾名思义,就是重复的使用数据,把得到的样本数据进行切分,组合为不同的训练集和测试集。
用训练集来训练模型,用测试集来评估模型预测的好坏。
在此基础上可以得到多组不同的训练集和测试集,某次训练集中的某样本在下次可能成为测试集中的样本,即所谓“交叉”。
下面我们将讲解几种不同的交叉验证的方法。
Holdout 交叉验证
Holdout 交叉验证就是将原始的数据集随机分成两组,一组为测试集,一组作为训练集。
我们使用训练集对模型进行训练,再使用测试集对模型进行测试。
记录最后的模型准确度作为衡量模型性能的指标。
这是最简单的交叉验证的方法,当我们需要针对大量数据进行简单快速的验证时,Holdout 验证是一个不错的方法。
通常,Holdout 交叉验证会将数据集的20%——30%作为测试集,而其余的数据作为训练集。
当测试集的占比较高的时候,会导致训练的数据不足,模型较为容易出错,准确度较低。
当测试集的占比较低的时候,会导致训练的数据过多,模型可能会出现过拟合或者欠拟合的问题。
#以下是Holdout 交叉验证的示例代码
#导入包,使用sklearn进行交叉验证
import pandas
from sklearn import datasets
from sklearn.model_selection import train_test_split
#将训练集的比例设为70%,测试集的比例设为30%
#可以通过更改这个数值来改变训练集的比例
TRAIN_SPLIT = 0.7
#设置以下diabetes数据集的列名
columns = [
'age', 'sex', 'bmi', 'map', 'tc', 'ldl', 'hdl', 'tch', 'ltg', 'glu'
]
#导入diabetes数据集
dataset = datasets.load_diabetes()
#创建数据集的dataframe
dataframe = pandas.DataFrame(dataset.data, columns=columns)
#看下数据集基本情况
dataframe.head()
#使用train_test_split对数据集进行分割
#train_test_split 是sklearn中分割数据集的常用方法
#train_size 设置了训练集的比例
x_train, x_test, y_train, y_test = train_test_split(
dataframe, dataset.target, train_size=TRAIN_SPLIT, test_size=1-TRAIN_SPLIT)
#看下数据集的条数
print("完整数据集的条数: {}".format(len(dataframe.index)))
#看下训练集和测试集的数据占比
print("训练集的条数(占比): {} (~{}%)".format(len(x_train), TRAIN_SPLIT*100))
print("测试集的条数(占比): {} (~{}%)n".format(len(x_test), (1-TRAIN_SPLIT)*100))
#下面两行代码可以看下具体的数据明细,取消注释即可
# print("Training data:n{}n".format(x_train))
# print("Test data:n{}".format(x_test))
完整数据集的条数: 442
训练集的条数(占比): 309 (~70.0%)
测试集的条数(占比): 133 (~30.000000000000004%)
K-Fold 交叉验证
K-Fold 交叉验证会将数据集分成K个部分,其中一个单独的样本作为测试集,而其余K-1个样本作为训练集。
交叉重复验证K次,每个子集都会作为测试集,对模型进行测试。
最终平均K次所得到的结果,最终得出一个单一的模型。
假如我们有100个数据点,并且分成十次交叉验证。
那么我们会将数据分成十个部分,每个部分有十个数据点。
我们可以分别对十个数据点进行验证,而对使用另外的90个数据点进行训练。
重复十次这样的操作,将得到十个模型。
我们对这些模型进行平均,最终得出一个适合的模型。
K-Fold 交叉验证适用于数据集样本比较小的情况。
#以下是K-Fold 交叉验证的示例代码
#导入相关的包
import numpy
#从sklearn中导入KFold
from sklearn.model_selection import KFold
#设置K值为3
NUM_SPLITS = 3
#创建一个数据集方便使用KFold Cross Validation
data = numpy.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]])
#看下数据情况
data
array([[ 1, 2],
[ 3, 4],
[ 5, 6],
[ 7, 8],
[ 9, 10],
[11, 12]])
#导入kfold交叉验证,将K值设置为3
kfold = KFold(n_splits=NUM_SPLITS)
#使用kfold分割数据
split_data = kfold.split(data)
#使用循环分别导出三次KFOLd的情况下训练集和测试集的数据内容
#将训练集设置为— 测试集设置为T
#使用for循环
for train, test in split_data:
#初始输出设置为空
output_train = ''
output_test = ''
#初始case设置为—
bar = ["-"] * (len(train) + len(test))
#创建子循环
for i in train:
#输出训练集的内容以及训练集的数据编号
output_train = "{}({}: {}) ".format(output_train, i, data[i])
for i in test:
#将测试集的case改成T
bar[i] = "T"
#输出测试集的内容以及测试集的数据编号
output_test = "{}({}: {}) ".format(output_test, i, data[i])
#训练集和测试集的直观标志
print("[ {} ]".format(" ".join(bar)))
print("训练集: {}".format(output_train))
print("测试集: {}n".format(output_test))
[ T T - - - - ]
训练集: (2: [5 6]) (3: [7 8]) (4: [ 9 10]) (5: [11 12])
测试集: (0: [1 2]) (1: [3 4])
[ - - T T - - ]
训练集: (0: [1 2]) (1: [3 4]) (4: [ 9 10]) (5: [11 12])
测试集: (2: [5 6]) (3: [7 8])
[ - - - - T T ]
训练集: (0: [1 2]) (1: [3 4]) (2: [5 6]) (3: [7 8])
测试集: (4: [ 9 10]) (5: [11 12])
Leave-P-Out 交叉验证
Leave-P-Out 交叉验证(LPOCV)使用样本中的某几项当做测试集,从样本中选取某几项的可能种类称为P值。
举个例子,当我们有四个数据点,而我们要将其中的两个数据点当做测试集。
则我们一共有 种可能性,直观的展现如下所示:(T代表测试集,—代表训练集)
1: [ T T - - ]
2: [ T - T - ]
3: [ T - - T ]
4: [ - T T - ]
5: [ - T - T ]
6: [ - - T T ]
下面是LPOCV的另外一种可视化:
LPOCV可以迅速提高模型的精确度,准确的描摹大样本数据集的特征信息。
模型使用LPOCV的迭代次数可以用 来计算。
其中N代表数据点的个数,而P代表了测试集数据点的个数。
例如我们有十个数据点,所选测试集数据点为三个。
那么LPOCV将迭代 次。
LPOCV的一个极端案例是LOOCV( Leave-One-Out Cross Validation)。
LOOCV限定了P的值等于1,这使得我们将迭代N次来评估模型。
LOOCV也可以看做是KFold交叉验证,其中
与KFold类似,LPOCV和LOOCV都可以遍历整个数据集。
因此,针对于小型的数据集,LPOCV和LOOCV十分有效。
#以下是LPOCV、LOOCV的示例代码
#导入包
import numpy
#从sklearn中导入LPOCV,LOOCV
from sklearn.model_selection import LeaveOneOut, LeavePOut
#设置P值等于2
P_VAL = 2
#定义一个导出分割数据的函数
def print_result(split_data):
for train, test in split_data:
#初始输出设置为空
output_train = ''
output_test = ''
#初始case设置为—
bar = ["-"] * (len(train) + len(test))
#创建子循环
for i in train:
#输出训练集的内容以及训练集的数据编号
output_train = "{}({}: {}) ".format(output_train, i, data[i])
for i in test:
#将测试集的case改成T
bar[i] = "T"
#输出测试集的内容以及测试集的数据编号
output_test = "{}({}: {}) ".format(output_test, i, data[i])
#训练集和测试集的直观标志
print("[ {} ]".format(" ".join(bar)))
print("训练集: {}".format(output_train))
print("测试集: {}n".format(output_test))
#创建一个需要分割的数据集
data = numpy.array([[1, 2], [3, 4], [5, 6], [7, 8]])
#分别导入LOOCV个LPOCV模型
loocv = LeaveOneOut()
lpocv = LeavePOut(p=P_VAL)
#分别使用LOOCV和LPOCV来分割数据
split_loocv = loocv.split(data)
split_lpocv = lpocv.split(data)
#分别输出LOOCV和LPOCV所对应的分割数据
print("LOOCV:n")
print_result(split_loocv)
print("LPOCV (where p = {}):n".format(P_VAL))
print_result(split_lpocv)
LOOCV:
[ T - - - ]
训练集: (1: [3 4]) (2: [5 6]) (3: [7 8])
测试集: (0: [1 2])
[ - T - - ]
训练集: (0: [1 2]) (2: [5 6]) (3: [7 8])
测试集: (1: [3 4])
[ - - T - ]
训练集: (0: [1 2]) (1: [3 4]) (3: [7 8])
测试集: (2: [5 6])
[ - - - T ]
训练集: (0: [1 2]) (1: [3 4]) (2: [5 6])
测试集: (3: [7 8])
LPOCV (where p = 2):
[ T T - - ]
训练集: (2: [5 6]) (3: [7 8])
测试集: (0: [1 2]) (1: [3 4])
[ T - T - ]
训练集: (1: [3 4]) (3: [7 8])
测试集: (0: [1 2]) (2: [5 6])
[ T - - T ]
训练集: (1: [3 4]) (2: [5 6])
测试集: (0: [1 2]) (3: [7 8])
[ - T T - ]
训练集: (0: [1 2]) (3: [7 8])
测试集: (1: [3 4]) (2: [5 6])
[ - T - T ]
训练集: (0: [1 2]) (2: [5 6])
测试集: (1: [3 4]) (3: [7 8])
[ - - T T ]
训练集: (0: [1 2]) (1: [3 4])
测试集: (2: [5 6]) (3: [7 8])
- 和开发讨论的一个数据变更需求(r9笔记第8天)
- Java案例-分数查等级程序
- Go语言的标准输入-scan 和bufio
- Java案例-判断给定年份是闰年
- 分分钟搭建Oracle环境 (r9笔记第23天)
- Java面试系列25-spring(4)-国际化、加入web容器,标签、事务等
- Java面试系列24-spring(3)-配置文件相关问题
- Java基础-day03-基础题
- 简单易学的机器学习算法——EM算法
- 备库跳归档恢复的有趣案例(r9笔记第19天)
- Java基础-day02-代码题
- 优化算法——拟牛顿法之L-BFGS算法
- 一次性能突发情况的紧急修复(r9笔记第18天)
- Java基础-day02-基础题
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ntp 服务开机启动失败
- 4.8 this关键字
- 使用Pyppeteer进行gmail模拟登录
- 一个没法商用,但是好玩有趣的 Python 手绘图形库!
- 使用豆瓣源安装python包
- [已解决]报错:ValueError: Expected 2D array, got scalar array instead
- [已解决]报错UnicodeDecodeError
- [已解决]报错Could not install packages due to an EnvironmentError
- 用Cython加速Python代码
- [已解决]windows安装docker的问题
- 使用VBA达到vlookup效果
- Excel简单应用
- Pandas异常值处理
- Pandas重复值处理
- Pandas缺失值处理