library(rsample)
## Warning: package 'rsample' was built under R version 4.6.1
library(glmnet)
## Warning: package 'glmnet' was built under R version 4.6.1
## Loading required package: Matrix
## Loaded glmnet 5.0
library(leaps)
## Warning: package 'leaps' was built under R version 4.6.1
library(pls)
## Warning: package 'pls' was built under R version 4.6.1
##
## Attaching package: 'pls'
## The following object is masked from 'package:stats':
##
## loadings
library(ggplot2)
library(plotly)
## Warning: package 'plotly' was built under R version 4.6.1
##
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ISLR2)
## Warning: package 'ISLR2' was built under R version 4.6.1
get_metrics <- function(actual, predicted) {
actual <- as.numeric(actual)
predicted <- as.numeric(predicted)
mse <- mean((actual - predicted)^2)
data.frame(
MSE = mse,
RMSE = sqrt(mse),
MAE = mean(abs(actual - predicted)),
R_Squared = 1 -
sum((actual - predicted)^2) /
sum((actual - mean(actual))^2)
)
}
get_test_results <- function(model, test_data, outcome) {
predictions <- predict(
model,
newdata = test_data
)
actual <- test_data[[outcome]]
metrics <- caret::postResample(
pred = predictions,
obs = actual
)
data.frame(
MSE = mean((actual - predictions)^2),
RMSE = unname(metrics["RMSE"]),
MAE = unname(metrics["MAE"]),
R_Squared = unname(metrics["Rsquared"])
)
}
iii. With Lasso it’s the best choice when a small number of predictors are associated with the response. The L1 penalty shrinks many coefficients to zero which automatically performs the variable selection. This will produce a simpler and more interpertable model that reduces overfitting.
iii. Ridge works well when many or most of the predictors have a moderate or smaller impact on the response. It shrinks the coefficients toward zeo which will reduce variance while keeping infromation from every variable in the model.
ii. When the relationship between the predictors and outcome is highly nonlinear squares, ridge, lasso and the other linear methods aren’t able to capture the true pattern. Nonlinear methods are designed to model more complex relationships.
data(College)
set.seed(5)
college_split <- initial_split(
College,
prop = 0.80,
strata = Apps
)
college_train <- training(college_split)
college_test <- testing(college_split)
college_lm <- lm(
Apps ~ .,
data = college_train
)
summary(college_lm)
##
## Call:
## lm(formula = Apps ~ ., data = college_train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5051.8 -440.4 -31.3 337.3 7047.5
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -730.14682 453.19962 -1.611 0.10768
## PrivateYes -458.33505 152.68876 -3.002 0.00280 **
## Accept 1.63555 0.04394 37.222 < 2e-16 ***
## Enroll -1.05569 0.20776 -5.081 5.00e-07 ***
## Top10perc 51.92719 6.21339 8.357 4.43e-16 ***
## Top25perc -15.46667 5.04137 -3.068 0.00225 **
## F.Undergrad 0.06488 0.03615 1.794 0.07324 .
## P.Undergrad 0.05654 0.03533 1.600 0.11009
## Outstate -0.08950 0.02126 -4.210 2.94e-05 ***
## Room.Board 0.10965 0.05422 2.022 0.04358 *
## Books -0.03267 0.25687 -0.127 0.89884
## Personal 0.08671 0.07383 1.174 0.24067
## PhD -10.78025 5.27253 -2.045 0.04133 *
## Terminal -1.72083 5.84066 -0.295 0.76838
## S.F.Ratio 29.68427 14.82947 2.002 0.04576 *
## perc.alumni 3.58905 4.58041 0.784 0.43360
## Expend 0.08969 0.01466 6.116 1.73e-09 ***
## Grad.Rate 10.08881 3.38278 2.982 0.00298 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1048 on 603 degrees of freedom
## Multiple R-squared: 0.9322, Adjusted R-squared: 0.9303
## F-statistic: 487.7 on 17 and 603 DF, p-value: < 2.2e-16
college_lm_pred <- predict(
college_lm,
newdata = college_test
)
college_lm_results <- get_metrics(
actual = college_test$Apps,
predicted = college_lm_pred
)
college_lm_results
x_college_train <- model.matrix(
Apps ~ .,
data = college_train
)[, -1]
x_college_test <- model.matrix(
Apps ~ .,
data = college_test
)[, -1]
y_college_train <- college_train$Apps
y_college_test <- college_test$Apps
college_ridge <- cv.glmnet(
x = x_college_train,
y = y_college_train,
alpha = 0,
nfolds = 10,
standardize = TRUE
)
college_ridge$lambda.min
## [1] 374.5783
college_ridge_pred <- predict(
college_ridge,
newx = x_college_test,
s = "lambda.min"
)
college_ridge_pred <- as.numeric(college_ridge_pred)
college_ridge_results <- get_metrics(
actual = y_college_test,
predicted = college_ridge_pred
)
data.frame(
Model = "Ridge",
Lambda = college_ridge$lambda.min,
college_ridge_results
)
college_lasso <- cv.glmnet(
x = x_college_train,
y = y_college_train,
alpha = 1,
nfolds = 10,
standardize = TRUE
)
college_lasso$lambda.min
## [1] 1.999011
college_lasso_pred <- predict(
college_lasso,
newx = x_college_test,
s = "lambda.min"
)
college_lasso_pred <- as.numeric(college_lasso_pred)
college_lasso_results <- get_metrics(
actual = y_college_test,
predicted = college_lasso_pred
)
college_lasso_results
college_lasso_coef <- as.matrix(
coef(
college_lasso,
s = "lambda.min"
)
)
college_lasso_selected <- college_lasso_coef[
college_lasso_coef[, 1] != 0,
,
drop = FALSE
]
college_lasso_count <- sum(
rownames(college_lasso_selected) != "(Intercept)"
)
college_lasso_count
## [1] 17
data.frame(
Model = "Lasso",
Lambda = college_lasso$lambda.min,
Nonzero_Coefficients = college_lasso_count,
college_lasso_results
)
college_pcr <- pcr(
Apps ~ .,
data = college_train,
scale = TRUE,
validation = "CV"
)
validationplot(
college_pcr,
val.type = "MSEP"
)
pcr_cv <- RMSEP(
college_pcr,
estimate = "CV"
)
pcr_cv_values <- drop(
pcr_cv$val[1, 1, ]
)
best_pcr_M <- which.min(pcr_cv_values) - 1
best_pcr_M
## 17 comps
## 17
college_pcr_pred <- predict(
college_pcr,
newdata = college_test,
ncomp = best_pcr_M
)
college_pcr_results <- get_metrics(
actual = college_test$Apps,
predicted = college_pcr_pred
)
data.frame(
Model = "PCR",
M_Selected = best_pcr_M,
college_pcr_results
)
college_pls <- plsr(
Apps ~ .,
data = college_train,
scale = TRUE,
validation = "CV"
)
validationplot(
college_pls,
val.type = "MSEP"
)
pls_cv <- RMSEP(
college_pls,
estimate = "CV"
)
pls_cv_values <- drop(
pls_cv$val[1, 1, ]
)
best_pls_M <- which.min(pls_cv_values) - 1
best_pls_M
## 16 comps
## 16
college_pls_pred <- predict(
college_pls,
newdata = college_test,
ncomp = best_pls_M
)
college_pls_results <- get_metrics(
actual = college_test$Apps,
predicted = college_pls_pred
)
data.frame(
Model = "PLS",
M_Selected = best_pls_M,
college_pls_results
)
college_results <- bind_rows(
data.frame(
Model = "Least Squares",
college_lm_results
),
data.frame(
Model = "Ridge",
college_ridge_results
),
data.frame(
Model = "Lasso",
college_lasso_results
),
data.frame(
Model = "PCR",
college_pcr_results
),
data.frame(
Model = "PLS",
college_pls_results
)
) |>
arrange(RMSE)
college_results
college_rmse_plot <- ggplot(
college_results,
aes(
x = reorder(Model, RMSE),
y = RMSE
)
) +
geom_col() +
coord_flip() +
labs(
title = "College Application Model Performance",
x = NULL,
y = "Test RMSE"
) +
theme_minimal()
college_rmse_plot
So It looks like overall that Ridge ended up being the best with a RMSE of ~995 so it’s predictions were off by about that many applicants on average. It’s R2 was one of the best with ~.92 so it accounts for ~92% of variation in the test set. The differences aren’t huge though as you can see the R2 are all above .90 and no RMSE is above 1035.
library(caret)
## Warning: package 'caret' was built under R version 4.6.1
## Loading required package: lattice
##
## Attaching package: 'caret'
## The following object is masked from 'package:pls':
##
## R2
## The following object is masked from 'package:rsample':
##
## calibration
data(Boston)
cv_control <- trainControl(
method = "repeatedcv",
number = 10,
repeats = 3,
savePredictions = "final"
)
## Least Squares
boston_lm <- train(
crim ~ .,
data = Boston,
method = "lm",
trControl = cv_control,
metric = "RMSE"
)
## Best Subset
boston_subset <- train(
crim ~ .,
data = Boston,
method = "leapSeq",
tuneGrid = data.frame(
nvmax = 1:(ncol(Boston) - 1)
),
trControl = cv_control,
metric = "RMSE"
)
boston_subset$bestTune
## Ridge Regression:
ridge_grid <- expand.grid(
alpha = 0,
lambda = 10^seq(-4, 4, length.out = 100)
)
boston_ridge <- train(
crim ~ .,
data = Boston,
method = "glmnet",
preProcess = c("center", "scale"),
tuneGrid = ridge_grid,
trControl = cv_control,
metric = "RMSE"
)
## Warning in nominalTrainWorkflow(x = x, y = y, wts = weights, info = trainInfo,
## : There were missing values in resampled performance measures.
## Lasso
lasso_grid <- expand.grid(
alpha = 1,
lambda = 10^seq(-4, 4, length.out = 100)
)
boston_lasso <- train(
crim ~ .,
data = Boston,
method = "glmnet",
preProcess = c("center", "scale"),
tuneGrid = lasso_grid,
trControl = cv_control,
metric = "RMSE"
)
## Warning in nominalTrainWorkflow(x = x, y = y, wts = weights, info = trainInfo,
## : There were missing values in resampled performance measures.
## PCR
boston_pcr <- train(
crim ~ .,
data = Boston,
method = "pcr",
preProcess = c("center", "scale"),
tuneGrid = data.frame(
ncomp = 1:(ncol(Boston) - 1)
),
trControl = cv_control,
metric = "RMSE"
)
## Model Comparison
boston_resamples <- resamples(
list(
Least_Squares = boston_lm,
Best_Subset = boston_subset,
Ridge = boston_ridge,
Lasso = boston_lasso,
PCR = boston_pcr
)
)
bwplot(
boston_resamples,
metric = "RMSE"
)
boston_results <- data.frame(
Method = c("Least Squares", "Best Subset", "Ridge", "Lasso", "PCR"),
RMSE = round(
c(
min(boston_lm$results$RMSE),
min(boston_subset$results$RMSE),
min(boston_ridge$results$RMSE),
min(boston_lasso$results$RMSE),
min(boston_pcr$results$RMSE)
),
3
)
)
boston_results
The best model looks to be Best Subset which has a 5.562 RMSE, it also sbustantial has a smaller spread that leans towards a lower RMSE in the box-whisker chart.Overall there’s not a ton of advantage for any of the methods over the others.
This just shows that the regularization and dimension reduction in methods didn’t substantially improve the predictiveness over the OLS for the Boston data set. Since all 5 methods got pretty similar RMSE it shows that the predictors contained enough information for least squares to perform comparably to the other methods.