统计学习导论(ISLR)
文章目录
- 统计学习导论(ISLR)
- 5 交叉验证和bootstrapR语言代码实战
- 5.1 验证集方法
- 5.2 留一法交叉验证(LOOCV)
- 5.3 K折交叉验证
- 5.4 Bootstrap
- 5.5 bootstrap进行区间估计
5 交叉验证和bootstrapR语言代码实战
我们将探讨本章介绍的重采样技术的r语言代码实现
5.1 验证集方法
我们使用验证集方法对Auto
数据集拟合各种线性模型来测试测试误差
首先,我们使用set.seed()函数设置随机种子来使得我们代码的复现,在包含随机性元素的交叉验证分析时,我们最好设置随机种子。使用sample()函数将样本随机分为两部分
# 导入相关库
library(ISLR2)
set.seed(1)#设置随机种子
# 将观测数据随机平均分成两部分,注意下述代码返回的是索引值
train <- sample(392,196)
我们通过lm()函数中的subset选择子集索引,在这里我们直接令subset=train
attach(Auto)
lm.fit <- lm(mpg~horsepower, data =Auto, subset = train)
我们可以通过[-train]来得到测试数据集,下面计算测试数据集上的MSE
mean((mpg-predict(lm.fit, Auto))[-train]^2)
23.2660086465003
可以看出线性回归的MSE为23.27,下面我们使用poly()函数来估计不同二次模型和三次模型的MSE
lm.fit2 <- lm(mpg ~ poly(horsepower, 2), data=Auto,
subset = train)
mean((mpg-predict(lm.fit2,Auto))[-train]^2)
18.7164594933828
lm.fit3 <- lm(mpg ~ poly( horsepower, 3), data = Auto,
subset = train)
mean((mpg-predict(lm.fit3,Auto))[-train]^2)
18.7940067973945
这些MSE分别为18.72和18.79。如果我们选择一个不同的训练集,那么我们将在验证集上获得一些不同的错误。
从测试集的MSE来看,二次拟合会比简单的线性拟合效果好,三次拟合并没有明显的提升拟合效果
5.2 留一法交叉验证(LOOCV)
loocv的结果可以直接使用glm()函数和cv.glm()函数得到。在第四章中,我们使用glm()函数拟合了logistic回归,还记得我们使用了family参数=binomal,如果我们不指定family值,则其默认是线性回归,和lm()函数一样。我们下面来验证这一结果
glm.fit <- glm(mpg~horsepower, data = Auto)
coef(glm.fit)
39.9358610211705
horsepower
-0.157844733353654
lm.fit <- lm(mpg~horsepower, data = Auto)
coef(lm.fit)
39.9358610211705
horsepower
-0.157844733353654
从结果可以看出上述两种方法得到的结果一样。下面我们使用glm()和cv.glm()来实现LOOCV,首先导入boot包
library(boot)
glm.fit <- glm(mpg~horsepower, data = Auto)
cv.err <- cv.glm(Auto,glm.fit)
cv.err$delta
- 24.2315135179293
- 24.2311440937562
可以看出上述得到的两个MSE几乎是一致的,因为LOOCV几乎每一次训练的结果差不多。注意,在使用cv.glm()时,不需要再指定train,会自动实现LOOCV过程。下面我们来看一下不同次方的多项式结果
cv.error <- rep(0,10)
for (i in 1:10) {
glm.fit <- glm(mpg~poly(horsepower,i),data= Auto)
cv.error[i] <- cv.glm(Auto, glm.fit)$delta[1]
}
cv.error
- 24.2315135179292
- 19.2482131244897
- 19.334984064029
- 19.4244303104303
- 19.0332138547041
- 18.9786436582254
- 18.8330450653182
- 18.9611507120532
- 19.0686299814599
- 19.490932299334
正如正文中的图5.4所示,在二次拟合的时候错误率较低较大
loocv <- data.frame(x,cv=cv.error)
library(ggplot2)
ggplot(loocv, aes(x, cv.error)) +geom_point() + geom_line(lwd=1,col='blue')
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-agKiOEwt-1648890761147)(output_22_0.png)]
5.3 K折交叉验证
cv.glm()函数也可以实现k折交叉验证,下面我们使用k=10,也是我们常用的一个k值。我们重新设置随机种子数,在Auto数据集拟合模型。
# 7是我的幸运数字,我就这么设置了
set.seed(7)
# 初始化向量来保存10折交叉验证的结果
cv_error_10 <- rep(0,10)
for (i in 1:10){
glm.fit <- glm(mpg~poly(horsepower,i), data = Auto)
cv_error_10[i] <- cv.glm(Auto,glm.fit,K = 10)$delta[1]
}
cv_error_10
- 24.1463716629577
- 19.3130825829741
- 19.434897545051
- 19.5493689322887
- 19.0736379228708
- 18.7058531603005
- 19.2522869995751
- 18.8552270777634
- 18.9304332711781
- 20.4425474405408
可以得出和loocv一直的结果,在二次拟合正确率提升较高,再更高次的拟合没有明显的提升模型正确率,还记得在LOOCV中$delta的两个MSE结果基本一致,但是在k-折交叉验证中,这两个数的结果略有区别,第一个是标准的k-cv,第二个是修正了偏差后的k-cv。在这个数据集中,两个值依然十分接近
glm.fit <- glm(mpg~poly(horsepower,i), data = Auto)
cv.glm(Auto,glm.fit,K = 10)$delta
- 19.0008700163861
- 18.9443399638009
5.4 Bootstrap
bootstrap方法的一大优点是,它几乎可以应用于所有情况。不需要复杂的数学计算。在R中只需要两个步骤。
- 首先,我们必须创建一个函数来计算我们要研究的统计量。
- 其次,我们使用boot()函数,通过重复采样数据集中的观察值来进行bootstrap
ISLR2包中的Portfolio
数据集是100对回报的模拟数据,按照正文5.2所述的方式生成。为了说明如何在这些数据上使用bootstrap,我们必须首先创建一个函数alpha(),需要两个参数,一个是数据集,另一个参数是索引,指定使用哪些数据来估计。然后,该函数根据选定的数据输出的估计值。根据我们在正文中给出的估计表达式,可以编写函数如下
alpha <- function(data,index){
X <- data$X[index]
Y <- data$Y[index]
(var(Y)-cov(X,Y))/(var(Y)+var(X)-2*cov(X,Y))
}
该函数输出给定数量数据集的,例如我们把元素数据集全部输入
alpha(Portfolio,1:100)
0.57583207459283
上述给出了的估计值,下面我们先使用sample()函数,从原始数据集中随机取100个观测值,replace设置为T,这样能选择重复的数据,默认值为F,不能选择重复的数据。下面相当于做了一个简单的bootstrap
set.seed(7)
alpha(Portfolio, sample(100, 100, replace = T))
0.538532591946793
我们需要做多次bootstrap,得到多个的估计值,最后取平均值得到,boot函数自动为我们计算了这些步骤,需要制定R参数表示次数,一般要大于1000次
alpha_hat <- boot(Portfolio,alpha,R=1000)
alpha_hat
ORDINARY NONPARAMETRIC BOOTSTRAP
Call:
boot(data = Portfolio, statistic = alpha, R = 1000)
Bootstrap Statistics :
original bias std. error
t1* 0.5758321 0.00105432 0.09045912
上述结果表明原始数据的,并且bootstrap估计
bootstrap方法可用于评估统计学习方法中系数估计和预测的稳定性。我们使用bootstrap来衡量和的稳定性,
首先定义函数得到回归系数
boot.fn <- function(data, index)
{coef(lm(mpg ~ horsepower, data = data, subset = index))}
boot.fn(Auto, 1:392)
39.9358610211705
horsepower
-0.157844733353654
set.seed(1)
boot.fn(Auto, sample(392, 392, replace = T))
40.3404516830189
horsepower
-0.163486837689938
# 使用boot()函数计算经过1000次bootstrap的标准差
boot(Auto, boot.fn, 1000)
ORDINARY NONPARAMETRIC BOOTSTRAP
Call:
boot(data = Auto, statistic = boot.fn, R = 1000)
Bootstrap Statistics :
original bias std. error
t1* 39.9358610 0.0549915227 0.841925746
t2* -0.1578447 -0.0006210818 0.007348956
通过bootstrap得到的参数的标准差估计值分别为0.84和0.0073,下面我们使用summary()函数得到系数的具体信息
summary(lm(mpg ~ horsepower, data = Auto))$coef
A matrix: 2 × 4 of type dbl
Estimate | Std. Error | t value | Pr(>|t|) | |
(Intercept) | 39.9358610 | 0.717498656 | 55.65984 | 1.220362e-187 |
horsepower | -0.1578447 | 0.006445501 | -24.48914 | 7.031989e-81 |
从上述结果来看,两个系数的标准差分别为0.72和0.0064,与bootstrap的结果略有不同,但这并不意味着bootstrap的结果有很大的偏差,相反,我们之前在线性回归中做了很多假设,但实际情况这些假设往往不满足,而bootstrap不需要任何假设,因此从这个角度来看,bootstrap得到的结果比summary()函数更准确
下面我们在使用bootstrap计算二次模型结果如下
boot.fn <- function(data, index)
coef(
lm(mpg ~ horsepower + I(horsepower^2), data = data, subset = index)
)
set.seed(1)
boot(Auto, boot.fn, 1000)
ORDINARY NONPARAMETRIC BOOTSTRAP
Call:
boot(data = Auto, statistic = boot.fn, R = 1000)
Bootstrap Statistics :
original bias std. error
t1* 56.900099702 3.511640e-02 2.0300222526
t2* -0.466189630 -7.080834e-04 0.0324241984
t3* 0.001230536 2.840324e-06 0.0001172164
summary(
lm(mpg ~ horsepower + I(horsepower^2), data = Auto)
)$coef
A matrix: 3 × 4 of type dbl
Estimate | Std. Error | t value | Pr(>|t|) | |
(Intercept) | 56.900099702 | 1.8004268063 | 31.60367 | 1.740911e-109 |
horsepower | -0.466189630 | 0.0311246171 | -14.97816 | 2.289429e-40 |
I(horsepower^2) | 0.001230536 | 0.0001220759 | 10.08009 | 2.196340e-21 |
5.5 bootstrap进行区间估计
我们可以根据bootstrap得到的统计量估计值和标准差估计值进一步计算其置信区间,可以使用boot.ci()函数计算期间
result <- boot(Portfolio,alpha,1000)
boot.ci(result)
Warning message in boot.ci(result):
"bootstrap variances needed for studentized intervals"
BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
Based on 1000 bootstrap replicates
CALL :
boot.ci(boot.out = result)
Intervals :
Level Normal Basic
95% ( 0.3888, 0.7527 ) ( 0.3826, 0.7430 )
Level Percentile BCa
95% ( 0.4086, 0.7690 ) ( 0.4006, 0.7565 )
Calculations and Intervals on Original Scale