python 留一交叉验证
基本原理
K折交叉验证
简单来说,K折交叉验证就是:
- 把数据集划分成K份,取出其中一份作为测试集,另外的K - 1份作为训练集。
- 通过训练集得到回归方程,再把测试集带入该回归方程,得到预测值。
- 计算预测值与真实值的差值的平方,得到平方损失函数(或其他的损失函数)。
- 重复以上过程,总共得到K个回归方程和K个损失函数,其中损失函数最小的回归方程就是最优解。
留一交叉验证
留一交叉验证是K折交叉验证的特殊情况,即:将数据集划分成N份,N为数据集总数。就是只留一个数据作为测试集,该特殊情况称为“留一交叉验证”。
代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
'''留一交叉验证''' import numpy as np # K折交叉验证 data = [[ 12 , 1896 ], [ 11 , 1900 ], [ 11 , 1904 ], [ 10.8 , 1908 ], [ 10.8 , 1912 ], [ 10.8 , 1920 ], [ 10.6 , 1924 ], [ 10.8 , 1928 ], [ 10.3 , 1932 ], [ 10.3 , 1936 ], [ 10.3 , 1948 ], [ 10.4 , 1952 ], [ 10.5 , 1956 ], [ 10.2 , 1960 ], [ 10.0 , 1964 ], [ 9.95 , 1968 ], [ 10.14 , 1972 ], [ 10.06 , 1976 ], [ 10.25 , 1980 ], [ 9.99 , 1984 ], [ 9.92 , 1988 ], [ 9.96 , 1992 ], [ 9.84 , 1996 ], [ 9.87 , 2000 ], [ 9.85 , 2004 ], [ 9.69 , 2008 ]] length = len (data) # 得到训练集和测试集 def Get_test_train(length, data, i): test_data = data[i] # 测试集 train_data = data[:] train_data.pop(i) # 训练集 return train_data, test_data # 得到线性回归直线 def Get_line(train_data): time = [] year = [] average_year_time = 0 average_year_year = 0 for i in train_data: time.append(i[ 0 ]) year.append(i[ 1 ]) time = np.array(time) year = np.array(year) average_year = sum (year) / length # year拔 average_time = sum (time) / length # time拔 for i in train_data: average_year_time = average_year_time + i[ 0 ] * i[ 1 ] average_year_year = average_year_year + i[ 1 ] * * 2 average_year_time = average_year_time / length # (year, time)拔 average_year_year = average_year_year / length # (year, year)拔 # 线性回归:t = w0 + w1 * x w1 = (average_year_time - average_year * average_time) / (average_year_year - average_year * average_year) w0 = average_time - w1 * average_year return w0, w1 # 得到损失函数 def Get_loss_func(w0, w1, test_data): time_real = test_data[ 0 ] time_predict = eval ( '{} + {} * {}' . format (w0, w1, test_data[ 1 ])) loss = (time_predict - time_real) * * 2 dic[ 't = {} + {}x' . format (w0, w1)] = loss return dic if __name__ = = '__main__' : dic = {} # 存放建为回归直线,值为损失函数的字典 for i in range (length): train_data, test_data = Get_test_train(length, data, i) w0, w1 = Get_line(train_data) Get_loss_func(w0, w1, test_data) dic = Get_loss_func(w0, w1, test_data) min_loss = min (dic.values()) best_line = [k for k, v in dic.items() if v = = min_loss][ 0 ] print ( '最佳回归直线:' , best_line) print ( '最小损失函数:' , min_loss) |
留一法交叉验证 Leave-One-Out Cross Validation
交叉验证法,就是把一个大的数据集分为 k 个小数据集,其中 k−1 个作为训练集,剩下的 1 11 个作为测试集,在训练和测试的时候依次选择训练集和它对应的测试集。这种方法也被叫做 k 折交叉验证法(k-fold cross validation)。最终的结果是这 k 次验证的均值。
此外,还有一种交叉验证方法就是 留一法(Leave-One-Out,简称LOO),顾名思义,就是使 k kk 等于数据集中数据的个数,每次只使用一个作为测试集,剩下的全部作为训练集,这种方法得出的结果与训练整个测试集的期望值最为接近,但是成本过于庞大。
我们用SKlearn库来实现一下LOO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
from sklearn.model_selection import LeaveOneOut # 一维示例数据 data_dim1 = [ 1 , 2 , 3 , 4 , 5 ] # 二维示例数据 data_dim2 = [[ 1 , 1 , 1 , 1 ], [ 2 , 2 , 2 , 2 ], [ 3 , 3 , 3 , 3 ], [ 4 , 4 , 4 , 4 ], [ 5 , 5 , 5 , 5 ]] loo = LeaveOneOut() # 实例化LOO对象 # 取LOO训练、测试集数据索引 for train_idx, test_idx in loo.split(data_dim1): # train_idx 是指训练数据在总数据集上的索引位置 # test_idx 是指测试数据在总数据集上的索引位置 print ( "train_index: %s, test_index %s" % (train_idx, test_idx)) # 取LOO训练、测试集数据值 for train_idx, test_idx in loo.split(data_dim1): # train_idx 是指训练数据在总数据集上的索引位置 # test_idx 是指测试数据在总数据集上的索引位置 train_data = [data_dim1[i] for i in train_idx] test_data = [data_dim1[i] for i in test_idx] print ( "train_data: %s, test_data %s" % (train_data, test_data)) |
data_dim1的输出:
train_index: [1 2 3 4], test_index [0]
train_index: [0 2 3 4], test_index [1]
train_index: [0 1 3 4], test_index [2]
train_index: [0 1 2 4], test_index [3]
train_index: [0 1 2 3], test_index [4]train_data: [2, 3, 4, 5], test_data [1]
train_data: [1, 3, 4, 5], test_data [2]
train_data: [1, 2, 4, 5], test_data [3]
train_data: [1, 2, 3, 5], test_data [4]
train_data: [1, 2, 3, 4], test_data [5]
data_dim2的输出:
train_index: [1 2 3 4], test_index [0]
train_index: [0 2 3 4], test_index [1]
train_index: [0 1 3 4], test_index [2]
train_index: [0 1 2 4], test_index [3]
train_index: [0 1 2 3], test_index [4]train_data: [[2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5]], test_data [[1, 1, 1, 1]]
train_data: [[1, 1, 1, 1], [3, 3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5]], test_data [[2, 2, 2, 2]]
train_data: [[1, 1, 1, 1], [2, 2, 2, 2], [4, 4, 4, 4], [5, 5, 5, 5]], test_data [[3, 3, 3, 3]]
train_data: [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [5, 5, 5, 5]], test_data [[4, 4, 4, 4]]
train_data: [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]], test_data [[5, 5, 5, 5]]
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/qq_43650934/article/details/108672624