set.seed(1)
college <- College
college$Private <- ifelse(college$Private == "Yes", 1, 0)
college_split <- initial_split(college, prop = 0.7)
college_train <- training(college_split)
college_test <- testing(college_split)
## [1] 1123.223
## [1] 1058.789
## [1] 1099.201
## [1] 1123.223
## [1] 17
## Selected M = 17
## [1] 1123.223
## 17 comps
## 17
set.seed(1)
boston <- Boston
boston_split <- initial_split(boston, prop = 0.7)
boston_train <- training(boston_split)
boston_test <- testing(boston_split)
boston_folds <- vfold_cv(boston, v = 10)
ridge_spec <- linear_reg(penalty = tune(), mixture = 0) %>%
set_engine("glmnet")
boston_recipe <- recipe(crim ~ ., data = boston) %>%
step_normalize(all_predictors())
ridge_wf <- workflow() %>%
add_recipe(boston_recipe) %>%
add_model(ridge_spec)
penalty_grid <- grid_regular(penalty(range = c(-4, 2)), levels = 100)
ridge_results <- tune_grid(
ridge_wf,
resamples = boston_folds,
grid = penalty_grid,
metrics = metric_set(yardstick::rmse, yardstick::rsq, yardstick::mae)
)
best_ridge <- select_best(ridge_results, metric = "rmse")
ridge_cv_metrics <- collect_metrics(ridge_results) %>%
filter(penalty == best_ridge$penalty) %>%
select(metric = .metric, estimate = mean) %>%
mutate(model = "Ridge Regression")
final_ridge_wf <- finalize_workflow(ridge_wf, best_ridge)
final_ridge_fit <- fit(final_ridge_wf, data = boston_train)
ridge_test_pred <- predict(final_ridge_fit, new_data = boston_test)
ridge_test_error <- mean((boston_test$crim - ridge_test_pred$.pred)^2)
sqrt(ridge_test_error)
## [1] 7.664965
set.seed(1)
lasso_spec <- linear_reg(penalty = tune(), mixture = 1) %>%
set_engine("glmnet")
lasso_wf <- workflow() %>%
add_recipe(boston_recipe) %>%
add_model(lasso_spec)
penalty_grid <- grid_regular(penalty(range = c(-4, 2)), levels = 100)
lasso_results <- tune_grid(
lasso_wf,
resamples = boston_folds,
grid = penalty_grid,
metrics = metric_set(yardstick::rmse, yardstick::rsq, yardstick::mae)
)
## → A | warning: A correlation computation is required, but `estimate` is constant and has 0
## standard deviation, resulting in a divide by 0 error. `NA` will be returned.
## There were issues with some computations A: x22There were issues with some computations A: x43There were issues with some computations A: x64There were issues with some computations A: x85There were issues with some computations A: x106There were issues with some computations A: x127There were issues with some computations A: x149There were issues with some computations A: x171There were issues with some computations A: x193There were issues with some computations A: x214There were issues with some computations A: x214
best_lasso <- select_best(lasso_results, metric = "rmse")
lasso_cv_metrics <- collect_metrics(lasso_results) %>%
filter(penalty == best_lasso$penalty) %>%
select(metric = .metric, estimate = mean) %>%
mutate(model = "Lasso Regression")
final_lasso_wf <- finalize_workflow(lasso_wf, best_lasso)
final_lasso_fit <- fit(final_lasso_wf, data = boston_train)
lasso_test_pred <- predict(final_lasso_fit, new_data = boston_test)
lasso_test_error <- mean((boston_test$crim - lasso_test_pred$.pred)^2)
sqrt(lasso_test_error)
## [1] 7.666177
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
lm_model <- lm(crim ~ zn + tax + rm + rad + ptratio + nox + medv + lstat + indus + dis + chas, data=boston_train)
boston_prediction <- predict(lm_model, newdata = boston_test)
test_error <- mean((boston_test$crim - boston_prediction)^2)
sqrt(test_error)
## [1] 7.590427
set.seed(1)
pcr_spec <- linear_reg() %>%
set_engine("lm")
boston_recipe_pcr <- recipe(crim ~ ., data = boston_train) %>%
step_dummy(all_nominal_predictors()) %>%
step_normalize(all_numeric_predictors()) %>%
step_pca(all_predictors(), num_comp = tune())
pcr_wf <- workflow() %>%
add_recipe(boston_recipe_pcr) %>%
add_model(pcr_spec)
pcr_grid <- grid_regular(num_comp(range = c(1, 20)), levels = 20)
pcr_results <- tune_grid(
pcr_wf,
resamples = boston_folds,
grid = pcr_grid,
metrics = metric_set(yardstick::rmse)
)
best_pcr <- select_best(pcr_results, metric = "rmse")
final_pcr_wf <- finalize_workflow(pcr_wf, best_pcr)
final_pcr_fit <- fit(final_pcr_wf, data = boston_train)
pcr_test_pred <- predict(final_pcr_fit, new_data = boston_test)
pcr_test_mse <- mean((boston_test$crim - pcr_test_pred$.pred)^2)
sqrt(pcr_test_mse)
## [1] 7.590291
set.seed(1)
pls_fit <- plsr(
crim ~ .,
data = boston_train,
scale = TRUE,
validation = "CV"
)
rm <- RMSEP(pls_fit)$val[1,,]
M <- which.min(rm) - 1
max_comps <- pls_fit$ncomp
if (M > max_comps) M <- max_comps
cat("Selected M =", M, "\n")
## Selected M = 10
pls_pred <- predict(pls_fit, newdata = boston_test, ncomp = M)
pls_test_mse <- mean((boston_test$crim - pls_pred)^2)
sqrt(pls_test_mse)
## [1] 7.590268
Given the results above, I would propose to stick with PCR and PLS models for this dataset.
These models do include all variables in the datset, which (from what I have read) is the norm for PCR and PLS given that they can account for such noise in the model.