交叉验证

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了交叉验证相关的知识,希望对你有一定的参考价值。

参考技术A

        交叉验证是在机器学习建立模型和验证模型参数时常用的办法。交叉验证就是重复使用数据,把得到的样本数据进行切分,组合为不同的训练集和测试集,用训练集来训练模型,用测试集来评估模型预测的好坏。在此基础上可以得到多组不同的训练和测试集,某次训练集中的某样本在下次可能成为测试集中的样本,即所谓“交叉”。
        交叉验证用在数据不是很充足的时候。比如,在日常项目中,对于普通适中问题,如果数据样本量小于一万条,我们就会采用交叉验证来训练优化选择模型。如果样本大于一万条的话,一般随机的把数据分成三份,一份为训练集(Training Set),一份为验证集(Validation Set),最后一份为测试集(Test Set)。用训练集来训练模型,用验证集来评估模型预测的好坏和选择模型及其对应的参数。把最终得到的模型再用于测试集,最终决定使用哪个模型以及对应参数。
         根据切分的方法不同,交叉验证分为下面三种:
        第一种,简单交叉验证。首先,随机的将样本数据分为两部分(比如:70%的训练集,30%的测试集),然后用训练集来训练模型,在测试集上验证模型及参数。接着,我们再把样本打乱,重新选择训练集合测试集,继续训练数据和检验模型。最后我们选择损失函数评估最优的模型和参数。
        第二种是S折交叉验证(S-Folder Cross Validation)。和第一种方法不同,S折交叉验证会把样本数据随机的分成S份,每次随机的选择S-1份作为训练集,剩下的1份做测试集。当这一轮完成后,重新随机选择S-1份来训练数据。若干轮(小于S)之后,选择损失函数评估最优的模型和参数。
        留一交叉验证(Leave-one-out Cross Validation),它是第二种情况的特例,此时S等于样本数N,这样对于N个样本,每次选择N-1个样本来训练数据,留一个样本来验证模型预测的好坏。此方法主要用于样本量非常少的情况,比如对于普通适中问题,N小于50时,一般采用留一交叉验证。
        通过反复的交叉验证,用损失函数来度量得到的模型的好坏,最终可以得到一个较好的模型。
        此外还有一种比较特殊的交叉验证方式,也是用于样本量少的时候,叫做自助法啊(bootstrapping)。比如有m个样本(m较小),每次在这m个样本中随机采集一个样本,放入训练集,采样完后把样本放回。这样重复采集n次,我们得到m个样本组成的训练集。当然,这m个样本中很有可能有重复的样本数据。同时,用没有被采样到的样本做测试集,这样接着进行交叉验证。由于我们的训练集有重复数据,这会改变数据的分布,因而训练结果会有估计偏差,因此,此种方法不是很常用,除非数据量很少,比如小于20个。

        将拿到的数据,分为训练和验证集。以下图为例:将数据分成5份,其中一份作为验证集。然后经过5次(组)的测试,每次都更换不同的验证集。即得到5组模型的结果,取平均值作为最终结果,又称5折交叉验证。

5、LASSO模型选择:交叉验证-AIC-BIC

参考技术A 5、LASSO模型选择:交叉验证-AIC-BIC

import time

import numpy as np

import matplotlib.pyplot as plt

from sklearn.linear_model import LassoCV, LassoLarsCV, LassoLarsIC

from sklearn import datasets

plt.rcParams['font.sans-serif'] = ['SimHei']

plt.rcParams['axes.unicode_minus'] = False

# 这是为了在执行np.log10时避免被零除

EPSILON = 1e-4

X, y = datasets.load_diabetes(return_X_y=True)

rng = np.random.RandomState(42)

X = np.c_[X, rng.randn(X.shape[0], 14)]  # 增加一些不好的特性

# 按照Lars的方法对数据进行规范化,以便进行比较

X /= np.sqrt(np.sum(X ** 2, axis=0))

# LassoLarsIC: 基于BIC/AIC准则的最小角回归

model_bic = LassoLarsIC(criterion='bic')

t1 = time.time()

model_bic.fit(X, y)

t_bic = time.time() - t1

alpha_bic_ = model_bic.alpha_

model_aic = LassoLarsIC(criterion='aic')

model_aic.fit(X, y)

alpha_aic_ = model_aic.alpha_

def plot_ic_criterion(model, name, color):

    criterion_ = model.criterion_

    plt.semilogx(model.alphas_ + EPSILON, criterion_, '--', color=color,

                linewidth=3, label='%s criterion' % name)

    plt.axvline(model.alpha_ + EPSILON, color=color, linewidth=3,

                label='alpha: %s estimate' % name)

    plt.xlabel(r'$\alpha$')

    plt.ylabel('criterion')

plt.figure()

plot_ic_criterion(model_aic, 'AIC', 'b')

plot_ic_criterion(model_bic, 'BIC', 'r')

plt.legend()

plt.title('信息-模型选择的标准 (训练时间: %.3fs)'

          % t_bic)

# LassoCV: 坐标下降

# 计算路径

print("Computing regularization path using the coordinate descent lasso...")

t1 = time.time()

model = LassoCV(cv=20).fit(X, y)

t_lasso_cv = time.time() - t1

# 显示结果

plt.figure()

ymin, ymax = 2300, 3800

plt.semilogx(model.alphas_ + EPSILON, model.mse_path_, ':')

plt.plot(model.alphas_ + EPSILON, model.mse_path_.mean(axis=-1), 'k',

        label='Average across the folds', linewidth=2)

plt.axvline(model.alpha_ + EPSILON, linestyle='--', color='k',

            label='alpha: CV estimate')

plt.legend()

plt.xlabel(r'$\alpha$')

plt.ylabel('Mean square error')

plt.title('每个折叠上的均方误差:坐标下降'

          '(训练时间 : %.2fs)' % t_lasso_cv)

plt.axis('tight')

plt.ylim(ymin, ymax)

# LassoLarsCV:最小角回归

# 计算路径

print("Computing regularization path using the Lars lasso...")

t1 = time.time()

model = LassoLarsCV(cv=20).fit(X, y)

t_lasso_lars_cv = time.time() - t1

# 显示结果

plt.figure()

plt.semilogx(model.cv_alphas_ + EPSILON, model.mse_path_, ':')

plt.semilogx(model.cv_alphas_ + EPSILON, model.mse_path_.mean(axis=-1), 'k',

            label='Average across the folds', linewidth=2)

plt.axvline(model.alpha_, linestyle='--', color='k',

            label='alpha CV')

plt.legend()

plt.xlabel(r'$\alpha$')

plt.ylabel('Mean square error')

plt.title('每折均方误差: Lars (训练时间 : %.2fs)'

          % t_lasso_lars_cv)

plt.axis('tight')

plt.ylim(ymin, ymax)

plt.show()

以上是关于交叉验证的主要内容,如果未能解决你的问题,请参考以下文章

交叉验证、留一交叉验证、自助法

交叉验证

5倍交叉验证如何理解

我是不是需要同时执行网格搜索(使用交叉验证)和交叉验证方法?

为啥交叉验证 RF 分类的性能比没有交叉验证的差?

使用交叉验证提高准确性,不使用交叉验证降低准确性