五种交叉验证方法的 R 语言实现
点击下方公众号,回复资料分享,收获惊喜
引言
交叉验证(Cross-Validation)是一种常用的模型评估方法,旨在评估机器学习模型在未知数据上的性能。它通过将数据集划分为多个互斥的子集,然后进行多次训练和测试,从而更全面地评估模型的泛化能力。
交叉验证方法
在机器学习中,常用的交叉验证方法有以下几种:
K 折交叉验证(K-Fold Cross Validation)
留一交叉验证(Leave-One-Out Cross Validation,简称LOOCV)
留 P 交叉验证(Leave-P-Out Cross Validation,简称LPOCV)
自助法交叉验证(Bootstrap Cross Validation)
分层 K 折交叉验证(Stratified K-Fold Cross Validation)
下面以线性回归作为目标模型,分别介绍这五种方法的原理及 R 语言实现。
K 折交叉验证
将原始数据随机分成 K 个子集(通常是等分),每次选择其中一个子集作为测试集,其他 K-1 个子集作为训练集,进行 K 次训练和验证,最后将 K 次验证结果平均得到最终的性能评估。K 折交叉验证是最常用的交叉验证方法。
K 折交叉验证的 R 语言实现需要使用caret
包中的 trainControl()
函数,设置参数method = "cv", number = 5
表示五折交叉验证:
# 导入所需包
library(ggplot2)
library(lattice)
library(caret)
# 以鸢尾花数据集为例
data(iris)
# 创建模型
set.seed(123)
model <- train(Sepal.Length~.,data=iris, method = "lm",
trControl = trainControl(method = "cv", number = 5))
# 查看交叉验证结果
print(model)
留一交叉验证
将原始数据集中的一个样本作为测试集,其他样本作为训练集,进行 N次训练和验证(N 为样本数量),每个测试集都只包含一个样本。LOOCV 在样本数量较小的情况下比较常用,但计算成本较高。
LOOCV 的 R 语言实现只需要在上述代码的基础上,将 trainControl()
函数改为 method = "LOOCV"
:
# 以鸢尾花数据集为例
data(iris)
set.seed(123)
# 创建模型
model <- train(Sepal.Length~.,data=iris, method = "lm",
trControl = trainControl(method = "LOOCV"))
# 查看交叉验证结果
print(model)
留 P 交叉验证
与留一交叉验证类似,但每次留 P 个样本作为测试集,其他样本作为训练集,进行多次训练和验证。LPOCV 是 LOOCV 的一种扩展形式,可以减小计算开销。
LPOCV 的 R 语言实现需要将 trainControl()
函数改为 method = "LGOCV", p = 0.7
,其中 p=0.7
表示 70% 的数据作为训练集 (注意:函数中的 p
和 LPOCV 中的 p
含义不同,并且在 R 中用LGOCV
来表示留 P 交叉验证):
# 以鸢尾花数据集为例
data(iris)
set.seed(123)
# 创建模型
model <- train(Sepal.Length~.,data=iris, method = "lm",
trControl = trainControl(method = "LGOCV", p = 0.7))
# 查看交叉验证结果
print(model)
自助法交叉验证
从原始数据集中有放回采样得到一个新的训练集,部分样本可能被重复采样,未被抽到的样本作为测试集。采样和验证的过程多次进行,最后将多次验证结果的平均值作为性能评估。自助法交叉验证适用于数据集较小,且难以有效划分训练集和测试集的情况。
自助法交叉验证的 R 语言实现需要先创建样本索引 createDataPartition(iris$Sepal.Length, times = 5, p = 0.7)
。其中,times
表示抽样的重复次数,p
表示训练集的比例:
# 以鸢尾花数据集为例
data(iris)
set.seed(123)
# 创建自助样本索引
# 创建自助样本索引
folds <- createDataPartition(iris$Sepal.Length, times = 5, p = 0.7)
# 创建模型
model <- train(Sepal.Length~.,data=iris, method = "lm",
trControl = trainControl(method = "boot", index = folds))
# 查看交叉验证结果
print(model)
分层 K 折交叉验证
在进行 K 折交叉验证时,每个子集的样本类别比例都与原始数据集中保持一致。这种交叉验证方法常用于处理不平衡数据集的情况。
分层 K 折交叉验证需要先根据分类变量的比例来划分数据子集,然后再进行交叉验证:
library(caret)
##根据分类变量划分子集
folds <- createFolds(iris$Species, k = 5)
##检验每个子集中的类别百分比是否等于原始样本
prop.table(table(iris$Species[folds$Fold1]))
prop.table(table(iris$Species[folds$Fold2]))
prop.table(table(iris$Species[folds$Fold3]))
prop.table(table(iris$Species[folds$Fold4]))
prop.table(table(iris$Species[folds$Fold5]))
prop.table(table(iris$Species))
cv_r <- list()
RMSE <- list()
MAE <- list()
for (i in 1:length(folds)) {
##将一个折作为测试集
test <- iris[folds[[i]],]
##其余折作为训练集
train <- iris[-folds[[i]],]
##构建模型
model <- lm(Sepal.Length~.,data=train)
pred <- predict(model,newdata = data.frame(test))
##选取一些评价指标
cv_r[[i]] <- summary(model)$r.squared
RMSE[[i]] <- sqrt(mean((pred-test$Sepal.Length)^ 2))
MAE[[i]] <- mean(abs(pred-test$Sepal.Length))
}
##每次迭代的交叉验证结果
cv_r_values <- unlist(cv_r)
cv_RMSE_values <- unlist(RMSE)
cv_MAE_values <- unlist(MAE)
##最终的结果
cv_mean_r <- mean(cv_r_values)
cv_mean_RMSE <- mean(cv_RMSE_values)
cv_mean_MAE <- mean(cv_MAE_values)
小结
交叉验证方法的选择取决于数据集的规模、性质以及具体的应用场景。注意,上述方法不适用于时间序列数据,因为时间序列具有时间依赖关系,不能随机选取训练集和测试集。 时间序列交叉验证的方法可见:时间序列交叉验证 R 语言实现。
可视化推文推荐
R可视乎|空间地理数据可视化(1)
空间地理数据可视化之 ggplot2 包及其拓展
空间地理数据可视化之 tmap 包及其拓展
R可视乎|创建乐高版马赛克图
R可视乎|用R给心仪的对象表白吧