We now review k-fold cross-validation.
Explain how k-fold cross-validation is implemented.
What are the advantages and disadvantages of k-fold cross-validation relative to:
In Chapter 4, we used logistic regression to predict the probability of default using income and balance on the Default data set. We will now estimate the test error of this logistic regression model using the validation set approach. Do not forget to set a random seed before beginning your analysis.
# install.packages("ISLR2")
# install.packages("boot")
library(ISLR2)
library(boot)
default_data <- Default
default_glm <- glm(default ~ income + balance,
data = default_data,
family = "binomial")
default_glm
##
## Call: glm(formula = default ~ income + balance, family = "binomial",
## data = default_data)
##
## Coefficients:
## (Intercept) income balance
## -1.154e+01 2.081e-05 5.647e-03
##
## Degrees of Freedom: 9999 Total (i.e. Null); 9997 Residual
## Null Deviance: 2921
## Residual Deviance: 1579 AIC: 1585
Using the validation set approach, estimate the test error of this model. In order to do this, you must perform the following steps:
# converting default column from "Yes" or "No" to 1 for Yes and 0 for no
default_data$default <- ifelse(default_data$default == "Yes", 1, 0)
set.seed(1)
default_train <- sample(1000, 500)
default_test <- default_data[-default_train,]
ii. Fit a multiple logistic regression model using only the training observations.
default_train_glm <- glm(default ~ income + balance,
data = default_data,
subset = default_train,
family = "binomial")
default_train_glm
##
## Call: glm(formula = default ~ income + balance, family = "binomial",
## data = default_data, subset = default_train)
##
## Coefficients:
## (Intercept) income balance
## -1.177e+01 3.176e-05 5.711e-03
##
## Degrees of Freedom: 499 Total (i.e. Null); 497 Residual
## Null Deviance: 134.7
## Residual Deviance: 78.33 AIC: 84.33
iii. Obtain a prediction of default status for each individual in the validation set by computing the posterior probability of default for that individual, and classifying the individual to the default category if the posterior probability is greater than 0.5.
default_preds <- predict(default_train_glm, default_data, type = "response")
default.preds <- ifelse(default_preds > 0.5, 1, 0)
iv. Compute the validation set error, which is the fraction of the observations in the validation set that are misclassified.
mean((default.preds != default_data$default)[-default_train])
## [1] 0.02652632
# training set will only have a 1/4 of the data points
set.seed(1)
default_train_250 <- sample(1000, 250)
default_test_250 <- default_data[-default_train_250,]
default_train_250_glm <- glm(default ~ income + balance,
data = default_data,
subset = default_train_250,
family = "binomial")
default_train_250_glm
##
## Call: glm(formula = default ~ income + balance, family = "binomial",
## data = default_data, subset = default_train_250)
##
## Coefficients:
## (Intercept) income balance
## -9.242e+00 9.932e-06 4.596e-03
##
## Degrees of Freedom: 249 Total (i.e. Null); 247 Residual
## Null Deviance: 70.81
## Residual Deviance: 48.89 AIC: 54.89
default_250_preds <- predict(default_train_250_glm, default_data, type = "response")
default_250.preds <- ifelse(default_250_preds > 0.5, 1, 0)
mean((default_250.preds != default_data$default)[-default_train_250])
## [1] 0.02666667
# training set will contain 3/4 of the data points
set.seed(1)
default_train_750 <- sample(1000, 750)
default_test_750 <- default_data[-default_train_750,]
default_train_750_glm <- glm(default ~ income + balance,
data = default_data,
subset = default_train_750,
family = "binomial")
default_train_750_glm
##
## Call: glm(formula = default ~ income + balance, family = "binomial",
## data = default_data, subset = default_train_750)
##
## Coefficients:
## (Intercept) income balance
## -1.224e+01 4.369e-05 5.816e-03
##
## Degrees of Freedom: 749 Total (i.e. Null); 747 Residual
## Null Deviance: 212.4
## Residual Deviance: 119.5 AIC: 125.5
default_750_preds <- predict(default_train_750_glm, default_data, type = "response")
default_750.preds <- ifelse(default_750_preds > 0.5, 1, 0)
mean((default_750.preds != default_data$default)[-default_train_750])
## [1] 0.0267027
# training set will contain 632 points and set seed will be at 5
set.seed(5)
default_train_632 <- sample(1000, 632)
default_test_632 <- default_data[-default_train_632,]
default_train_632_glm <- glm(default ~ income + balance,
data = default_data,
subset = default_train_632,
family = "binomial")
default_train_632_glm
##
## Call: glm(formula = default ~ income + balance, family = "binomial",
## data = default_data, subset = default_train_632)
##
## Coefficients:
## (Intercept) income balance
## -1.065e+01 3.445e-05 4.966e-03
##
## Degrees of Freedom: 631 Total (i.e. Null); 629 Residual
## Null Deviance: 177.5
## Residual Deviance: 112 AIC: 118
default_632_preds <- predict(default_train_632_glm, default_data, type = "response")
default_632.preds <- ifelse(default_632_preds > 0.5, 1, 0)
mean((default_632.preds != default_data$default)[-default_train_632])
## [1] 0.02690009
The main thing I noticed when changing the training set size, is that the test error did not change much. The initial test (half the data points in the training set) the error was 0.02652632 but as the size change the only by the ten-thousands place (example: 0.02690009).
# creating dummy variable for student
default_data$student <- ifelse(default_data$student == "Yes", 1, 0)
updated_default_glm <- glm(default ~ income + balance + student,
data = default_data,
family = "binomial")
updated_default_glm
##
## Call: glm(formula = default ~ income + balance + student, family = "binomial",
## data = default_data)
##
## Coefficients:
## (Intercept) income balance student
## -1.087e+01 3.033e-06 5.737e-03 -6.468e-01
##
## Degrees of Freedom: 9999 Total (i.e. Null); 9996 Residual
## Null Deviance: 2921
## Residual Deviance: 1572 AIC: 1580
set.seed(1)
updated_default_train <- sample(1000, 500)
updated_default_test <- default_data[-updated_default_train,]
updated_default_train_glm <- glm(default ~ income + balance + student,
data = default_data,
subset = updated_default_train,
family = "binomial")
updated_default_train_glm
##
## Call: glm(formula = default ~ income + balance + student, family = "binomial",
## data = default_data, subset = updated_default_train)
##
## Coefficients:
## (Intercept) income balance student
## -1.072e+01 1.949e-06 5.931e-03 -1.151e+00
##
## Degrees of Freedom: 499 Total (i.e. Null); 496 Residual
## Null Deviance: 134.7
## Residual Deviance: 77.14 AIC: 85.14
updated_default_preds <- predict(updated_default_train_glm, default_data, type = "response")
updated_default.preds <- ifelse(updated_default_preds > 0.5, 1, 0)
mean((updated_default.preds != default_data$default)[-updated_default_train])
## [1] 0.02673684
After adding creating a dummy variable for student and adding it into logistical regression, it did not have a significant impact to the test error. After using the updated model and training the set, the error lied in the same range of the initial tests in the previous questions.
We continue to consider the use of a logistic regression model to predict the probability of default using income and balance on the Default data set. In particular, we will now compute estimates for the standard errors of the income and balance logistic regression coefficients in two different ways: (1) using the bootstrap, and (2) using the standard formula for computing the standard errors in the glm() function. Do not forget to set a random seed before beginning your analysis.
default.glm <- glm(default ~ income + balance,
data = default_data,
family = "binomial")
summary(default.glm)
##
## Call:
## glm(formula = default ~ income + balance, family = "binomial",
## data = default_data)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.154e+01 4.348e-01 -26.545 < 2e-16 ***
## income 2.081e-05 4.985e-06 4.174 2.99e-05 ***
## balance 5.647e-03 2.274e-04 24.836 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 2920.6 on 9999 degrees of freedom
## Residual deviance: 1579.0 on 9997 degrees of freedom
## AIC: 1585
##
## Number of Fisher Scoring iterations: 8
boot.fn <- function(data, index) {
coef(glm(default ~ income + balance,
data = data,
family = "binomial",
subset = index))
}
boot.fn(default_data, 1:1000)
## (Intercept) income balance
## -1.155359e+01 3.074546e-05 5.609161e-03
set.seed(1)
boot(default_data, boot.fn, R = 1000)
##
## ORDINARY NONPARAMETRIC BOOTSTRAP
##
##
## Call:
## boot(data = default_data, statistic = boot.fn, R = 1000)
##
##
## Bootstrap Statistics :
## original bias std. error
## t1* -1.154047e+01 -3.945460e-02 4.344722e-01
## t2* 2.080898e-05 1.680317e-07 4.866284e-06
## t3* 5.647103e-03 1.855765e-05 2.298949e-04
When comparing the estimated standard errors between glm() and bootstrap function, it can be noticed that the standard errors are very close to one another. The estimated standard error for the income intercept are within .120 of each other and the estimated standard error for the balance intercept are within .02 of each other.
We will now consider the Boston housing data set, from the ISLR2 library.
# u hat
mean_of_medv <- mean(Boston$medv)
mean_of_medv
## [1] 22.53281
#
num <- sd(Boston$medv)
denom <- sqrt(nrow(Boston))
se_u_hat <- num / denom
se_u_hat
## [1] 0.4088611
boston.boot.fn <- function(data, index) {
mean(data$medv[index])
}
boston.boot.fn(Boston, 1:506)
## [1] 22.53281
set.seed(1)
boot(Boston, boston.boot.fn, R = 1000)
##
## ORDINARY NONPARAMETRIC BOOTSTRAP
##
##
## Call:
## boot(data = Boston, statistic = boston.boot.fn, R = 1000)
##
##
## Bootstrap Statistics :
## original bias std. error
## t1* 22.53281 0.007650791 0.4106622
Using bootstap, the standard error was only .01 greater than the standard error calculated in part b.
set.seed(1)
boot_medv <- boot(Boston, boston.boot.fn, R = 1000)
confidence_lower <- mean_of_medv - (2*(sd(boot_medv$t)))
confidence_upper <- mean_of_medv + (2*(sd(boot_medv$t)))
c(confidence_lower, confidence_upper)
## [1] 21.71148 23.35413
t.test(Boston$medv)
##
## One Sample t-test
##
## data: Boston$medv
## t = 55.111, df = 505, p-value < 2.2e-16
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## 21.72953 23.33608
## sample estimates:
## mean of x
## 22.53281
The confidence interval provided by the T test and the confidence interval calculated are nearly identical. The lower limit of the confidence interval have a difference of .05 and the upper limit of the confidence interval have a difference of .04.
median_medv <- median(Boston$medv)
median_medv
## [1] 21.2
boot_median.fn <- function(data, index) {
median(data$medv[index])
}
set.seed(1)
boot(Boston, boot_median.fn, R = 1000)
##
## ORDINARY NONPARAMETRIC BOOTSTRAP
##
##
## Call:
## boot(data = Boston, statistic = boot_median.fn, R = 1000)
##
##
## Bootstrap Statistics :
## original bias std. error
## t1* 21.2 0.02295 0.3778075
When using the median, bootstrap calculated a lower standard error than when using the mean of medv. The standard error using median medv is lower by .04.
u_hat_0.1 <- quantile(Boston$medv, 0.1)
u_hat_0.1
## 10%
## 12.75
boot_10_percent.fn <- function(data, index) {
quantile(data$medv[index], 0.1)
}
set.seed(1)
boot(Boston, boot_10_percent.fn, R = 1000)
##
## ORDINARY NONPARAMETRIC BOOTSTRAP
##
##
## Call:
## boot(data = Boston, statistic = boot_10_percent.fn, R = 1000)
##
##
## Bootstrap Statistics :
## original bias std. error
## t1* 12.75 0.0339 0.4767526
After using bootstrap to find the standard error of \(\hat{µ}\), the tenth percentile provides the largest standard error. This standard error is .47 and is higher than the inital test on the mean by .06.