模型选择和交叉验证

模型选择

holdout方法

在典型的机器学习应用中,为进一步提高模型在预测未知数据的性能,还要对不同的参数设置进行调优和比较,该过程称为模型选择。指的是针对某一特定问题,调整参数以寻求最优超参数的过程。
假设要在10个不同次数的二项式模型之间进行选择:

1.hθ(x)=θ0+θ1x2.hθ(x)=θ0+θ1x+θ2x23.hθ(x)=θ0+θ1x++θ2x310.hθ(x)=θ0+θ1x++θ10x10 1. h θ ( x ) = θ 0 + θ 1 x 2. h θ ( x ) = θ 0 + θ 1 x + θ 2 x 2 3. h θ ( x ) = θ 0 + θ 1 x + ⋯ + θ 2 x 3 ⋯ 10. h θ ( x ) = θ 0 + θ 1 x + ⋯ + θ 10 x 10

显然越高次数的多项式模型越能够适应我们的训练数据集,但是适应训练数据集并不代表着能推广至一般情况。我们应该选择一个更能适应一般情况的模型。如果在模型选择过程中不断重复使用相同的测试数据,这样的话测试数据就变成了训练数据的一部分,模型更容易陷入过拟合。
于是我们将数据集分为训练集,验证集和测试集。训练数据集用于不同模型的拟合,模型在验证集上的性能表现作为模型选择的标准,测试集作为最终的性能评估。使用 60%的数据作为训练集, 使用 20%的数据作为交叉验证集, 使用 20%的数据
作为测试集.

具体的模型选择方法为:
1. 使用训练集训练出 10 个模型
Train error:

Jtrain(θ)=12mi=1m(hθ(x(i))y(i))2 J t r a i n ( θ ) = 1 2 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2

2. 用 10 个模型分别对交叉验证集计算得出交叉验证误差(代价函数的值)
Cross validation error:
Jcv(θ)=12mcvi=1mcv(hθ(x(i)cv)y(i)cv)2 J c v ( θ ) = 1 2 m c v ∑ i = 1 m c v ( h θ ( x c v ( i ) ) − y c v ( i ) ) 2

3. 选取代价函数值最小的模型: minθJcv(θ) min θ J c v ( θ )
4. 用步骤 3 中选出的模型对测试集计算得出推广误差(代价函数的值)
Test error:
Jtest(θ)=12mtesti=1mtest(hθ(x(i)test)y(i)cv)2 J t e s t ( θ ) = 1 2 m t e s t ∑ i = 1 m t e s t ( h θ ( x t e s t ( i ) ) − y c v ( i ) ) 2

缺点:模型性能的皮评估对训练数据划分为训练及验证子集的方法是敏感的;评价的结果是敏感的;评价的结果会随样本的不同而发生变化。

k折交叉验证

K折交叉验证中,不重复地随机将训练数据集划分为K个,其中k-1个用于模型的训练,剩余的1个用于测试。重复此过程k次,就得到了k个模型及对模型性能的评价。该种方法对数据划分的敏感性较低。
下图展示了k折交叉验证,k=10,训练数据集被划分为10块,在10次迭代中,每次迭代中都将9块用于训练,剩余的1块用于模型的评估。10块数据集作用于某一分类器,分类器得到的性能评价指标为 Ei,i=1,2,,10 E i , i = 1 , 2 , ⋯ , 10 ,可用来计算模型的估计平均性能 11010i=1Ei 1 10 ∑ i = 1 10 E i

模型选择和交叉验证_第1张图片
K折交叉验证中k的标准值为10,对大多数应用来说都时合理的。如果训练集相对较小,可以增大k值,这样将会有更多的数据用于进行训练,这样性能的评估结果也会得到较小的偏差。但是k值得增加会导致交叉验证算法的时间延长,并使得训练块高度相似,无法发挥交叉验证的效果。如果数据集较大,可以选择较小的k值,降低在不同数据块的重复计算成本,同时训练快比例小但是依然有大量的训练数据。

sklearn实现交叉验证:找到KNN算法的最佳k值

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier  # K最近邻(kNN,k-NearestNeighbor)分类算法
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt

# 加载iris数据集
iris = load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

if __name__ == '__main__':

    k_scores = []
    # 由迭代的方式来计算不同k对模型的影响,并返回交叉验证后的平均准确率
    for k in range(1, 31):
        # 采用k个最近邻
        knn = KNeighborsClassifier(n_neighbors=k)
        '''
        n_jobs为将交叉验证过程分布到的CPU核心数量,若>1,需要放到"if __name__ == '__main__'"中
        '''
        scores = cross_val_score(knn, X_train, y_train, cv=10, n_jobs=1)
        k_scores.append(scores.mean())

    # 可视化数据
    plt.plot(range(1, 31), k_scores)
    plt.xlabel('Value of K for KNN')
    plt.ylabel('Cross-Validated Accuracy')
    plt.show()

模型选择和交叉验证_第2张图片

分层k折交叉验证

分层交叉验证中,类别比例在每个分块中保持一致,使得每个分块中的类别比例与训练数据集的整体比例一致,在sklearn中使用StratifiedKFold,其中cross_val_score默认也采用分层k折交叉验证

from sklearn.model_selection import StratifiedKFold
import numpy as np

X = np.array([[1, 2], [3, 4], [1, 2], [3, 4], [2, 3], [4, 5]])
y = np.array([0, 0, 0, 1, 1, 1])
skf = StratifiedKFold(n_splits=3)
skf.get_n_splits(X, y)
for train_index, valid_index in skf.split(X, y):
    print('Train:', train_index, 'Valid:', valid_index)
Train: [1 2 4 5] Valid: [0 3]
Train: [0 2 3 5] Valid: [1 4]
Train: [0 1 3 4] Valid: [2 5]

你可能感兴趣的:(python机器学习)