library(tidyverse)
library(knitr)
library(ggthemes)
library(ISLR)
library(ggforce)
theme_set(theme_bw())
Combine simple models in order to obtain a more powerful model
Taken from Professor Wells
Additional instructions: don’t scroll past the white space until we get there
At the Grinnell Walmart, consider the grocery section (south side of the store, to the left when you walk in). Write your answer to the following question on a sheet of paper. Do not consult your neighbor: Note this may have changed with the remodel, but I’m using the old numbers
Suppose we have \(m\) different models to predict \(Y\) based on \(X_1, \dots, X_n\). Suppose \(\hat{Y}_i\) is the prediction made by the \(i\)th model.
A simple ensemble model makes a prediction \(\hat{Y}\) as the weighted average of the predictions from each model: \[ \hat{Y} = w_1 \hat{Y}_1 + \dots + w_m \hat{Y}_m \qquad \textrm{where }w_1 + \dots w_m = 1, \quad w_i \geq 0 \]
Advantages of ensemble models?
Disadvantages?
Question 3 Suppose we have a sample with 4 unique observations \(\{x_1,x_2, x_3, x_4\}\) and create a bootstrap sample.
Question 4 Now suppose we have \(n\) unique observations \(\{x_1, \dots, x_n\}\) and we create a bootstrap sample.
Suppose we only have one training set, but still want to build an ensemble of regression tree models. How can we do it?
We return to the pdxTrees data set, this time expanding
both our data set size and number of predictors:
library(pdxTrees)
my_pdxTrees <- get_pdxTrees_parks(park = c("Berkeley Park", "Woodstock Park", "Westmoreland Park", "Mt Scott Park", "Powell Park", "Kennilworth Park", "Sellwood Park", "Crystal Springs Rhododendron Garden", "Laurelhurst Park"))%>% mutate_if(is.character, as.factor) %>% dplyr::select(DBH, Condition, Tree_Height, Crown_Width_NS, Crown_Width_EW, Crown_Base_Height, Functional_Type, Mature_Size, Carbon_Sequestration_lb) %>% drop_na()
names(my_pdxTrees)
## [1] "DBH" "Condition"
## [3] "Tree_Height" "Crown_Width_NS"
## [5] "Crown_Width_EW" "Crown_Base_Height"
## [7] "Functional_Type" "Mature_Size"
## [9] "Carbon_Sequestration_lb"
dim(my_pdxTrees)
## [1] 3015 9
set.seed(1)
library(rsample)
my_pdxTrees_split <- initial_split(my_pdxTrees )
my_pdxTrees_train <- training(my_pdxTrees_split)
my_pdxTrees_test <- testing(my_pdxTrees_split)
Carbon_Sequestration_lb, now using more data and more
predictors?rsample:library(rsample)
set.seed(1115)
pdx_bootstrap <- bootstraps(my_pdxTrees_train, times = 4)
library(rpart)
get_tree <- function(split){
bootstrap_sample <- analysis(split)
model <- rpart(Carbon_Sequestration_lb ~., data = bootstrap_sample)
}
pdx_bootstrap$model <- map(pdx_bootstrap$splits, get_tree)
par(mfcol = c(2, 2), mar = c(1, 1, 1, 1))
library(rpart.plot)
rpart.plot(pdx_bootstrap$model[[1]], box.palette = "Greens")
rpart.plot(pdx_bootstrap$model[[2]], box.palette = "Greens")
rpart.plot(pdx_bootstrap$model[[3]], box.palette = "Greens")
rpart.plot(pdx_bootstrap$model[[4]], box.palette = "Greens")
get_predictions <- function(model){
predictions <- predict(model, my_pdxTrees_test)
data.frame(obs = my_pdxTrees_test$Carbon_Sequestration_lb, preds = predictions)
}
pdx_bootstrap$predictions <- map(pdx_bootstrap$model, get_predictions)
rmse on each using
yardsticklibrary(yardstick)
results <- map_dfr(pdx_bootstrap$predictions, rmse, obs, preds)
results
## # A tibble: 4 × 3
## .metric .estimator .estimate
## <chr> <chr> <dbl>
## 1 rmse standard 14.0
## 2 rmse standard 14.3
## 3 rmse standard 14.3
## 4 rmse standard 13.1
mean(results$.estimate)
## [1] 13.89024
some_preds <- tibble(
tree1 = pdx_bootstrap[[4]][[1]]$preds,
tree2 = pdx_bootstrap[[4]][[2]]$preds,
tree3 = pdx_bootstrap[[4]][[3]]$preds,
tree4 = pdx_bootstrap[[4]][[4]]$preds
) %>% rowwise() %>% mutate(bagged = mean(c_across( )))
some_preds%>% head()
## # A tibble: 6 × 5
## # Rowwise:
## tree1 tree2 tree3 tree4 bagged
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 49.0 30.4 52.2 32.5 41.0
## 2 34.7 38.0 43.3 32.8 37.2
## 3 56.8 84.0 67.6 72.9 70.3
## 4 30.6 46.6 38.8 37.8 38.4
## 5 56.8 65.7 67.6 72.9 65.7
## 6 56.8 84.0 89.1 72.9 75.7
bagged_results <- data.frame(obs = my_pdxTrees_test$Carbon_Sequestration_lb, preds = some_preds$bagged)
rbind(results, rmse(bagged_results, truth = obs, estimate = preds )) %>% mutate(model = c("tree 1", "tree 2", "tree 3", "tree 4", "bagged")) %>% select(model, everything())
## # A tibble: 5 × 4
## model .metric .estimator .estimate
## <chr> <chr> <chr> <dbl>
## 1 tree 1 rmse standard 14.0
## 2 tree 2 rmse standard 14.3
## 3 tree 3 rmse standard 14.3
## 4 tree 4 rmse standard 13.1
## 5 bagged rmse standard 12.3
Question 4 If 4 trees improved performance over 1, what if we bagged 10 trees? 100?
Audience
Suppose we have a sample with 4 unique observations \(\{x_1,x_2, x_3, x_4\}\) and create a bootstrap sample.
What is the probability that \(x_1\) is not the 1st element in the bootstrap sample? What is the probability that it is not the 2nd?
What is the probability that \(x_1\) is not in the bootstrap sample at all?
What is the probability that \(x_2\) is not in the bootstrap sample?
Now suppose we have \(n\) unique observations \(\{x_1, \dots, x_n\}\) and we create a bootstrap sample.
What is the probability that \(x_1\) is not in the bootstrap sample?
What is the probability that an arbitrary observation \(x_i\) is not in the bootstrap sample?
What happens to the probability that an arbitrary observation is not in the sample, as \(n\) goes to infinity?
Question 4 If 4 trees improved performance over 1, what if we bagged 10 trees? 100?
set.seed(11)
library(randomForest)
rfmodels<-list()
tree_size <- c(1:5,10*1:5, 75,100, 150, 200)
for (i in tree_size){
rfmodels[[i]]<-randomForest(Carbon_Sequestration_lb ~ ., data = my_pdxTrees_train, ntree = i , mtry = 8, na.action = na.roughfix )
}
results <- data.frame()
for (i in tree_size){
preds <-predict(rfmodels[[i]], newdata = my_pdxTrees_test)
obs <- my_pdxTrees_test$Carbon_Sequestration_lb
results <- rbind(results, data.frame(n_trees = i, preds, obs))
}
bagged_RMSE <- results %>% group_by(n_trees) %>% rmse(truth = obs, estimate = preds)
bagged_RMSE %>%
ggplot( aes( x = n_trees, y = .estimate))+geom_point()+theme_bw()+geom_line()+labs(x = "Number of Trees", y = "RMSE", title = "RMSE of Bagged Tree, Based on Number of Trees Included")
Greatest gains by adding a small number of additional trees
Moderately small gains thereafter