Skip to Content
Course content

59: Building Models with caret

Click on the "Edit" button in the top corner of the screen to edit your slide content.

If you've tried to build a few different types of models in R—say, a random forest, then a support vector machine, then a gradient boosting machine—you've probably noticed a frustrating pattern. Every single package has its own way of doing things. One wants a formula, another wants a matrix and a vector, and the way they handle hyperparameter tuning is completely different for each. It's a mess.

I used to spend half my time just looking up the documentation for the specific package I was using, rather than actually thinking about the data. That's why we're using caret (which stands for Classification And REgression Training). It basically acts as a wrapper, giving us a unified interface for hundreds of different algorithms.

The headache of fragmented syntax

Let's start with a common task: predicting the species of an iris flower. Now, I know iris is the "Hello World" of data science, but it's perfect for demonstrating the workflow without getting bogged down in data cleaning.

If I wanted to do this manually with a Random Forest, I'd load the randomForest library and run something like this:

library(randomForest)
rf_model <- randomForest(Species ~ ., data = iris)
print(rf_model)

That works fine for a quick look. But here's where I usually hit a wall: how do I know if mtry (the number of variables randomly sampled as candidates at each split) is optimized? I'd have to write a for loop, test a dozen different values, store the results in a dataframe, and plot the accuracy. It's tedious and prone to typos.

Letting caret handle the heavy lifting

Instead of writing my own tuning loops, I'll use caret::train. The goal is to tell caret: "I want a random forest, here is my data, and I want you to figure out the best settings for me."

library(caret)

# First attempt at a caret model
model_rf <- train(Species ~ ., 
                 data = iris, 
                 method = "rf")

When I run this, I see a lot of output in the console. caret is actually running the model multiple times with different values for mtry. It's doing that manual loop I mentioned, but behind the scenes. If I look at model_rf, it tells me exactly which value of mtry gave the best accuracy. This is much cleaner.

Controlling the chaos with trainControl

Wait, there's a problem. By default, train uses a basic resampling method. In a real project, I can't just trust a single split of the data; I need cross-validation to make sure the model isn't just memorizing the training set.

I need a way to tell the train function how to evaluate the model before I actually tell it which model to build. This is where trainControl comes in. It's like a configuration file for the training process.

# Setting up 10-fold cross-validation
my_control <- trainControl(method = "cv", number = 10)

# Now I plug that control object into the train function
model_rf_cv <- train(Species ~ ., 
                    data = iris, 
                    method = "rf", 
                    trControl = my_control)

Now, caret splits the data into 10 pieces, trains on 9, tests on 1, and repeats that 10 times. It takes longer to run, but I can sleep better knowing the accuracy score is actually meaningful.

Testing a different brain

Here is the "aha!" moment with caret. Suppose I have a hunch that a K-Nearest Neighbors (KNN) model might actually outperform the Random Forest. In the old way, I'd have to load a new library, learn a new syntax, and write a new tuning loop for k.

With caret, I only change one word:

model_knn <- train(Species ~ ., 
                    data = iris, 
                    method = "knn", 
                    trControl = my_control, 
                    preProcess = c("center", "scale"))

I added preProcess = c("center", "scale") because KNN relies on distance, and if one variable is in the thousands and another is a decimal, the large one will hijack the model. caret handles this scaling internally during the training process, which prevents "data leakage" (a common mistake where you scale your data using the whole dataset instead of just the training fold).

Now I have two models, model_rf_cv and model_knn, both built with the exact same validation logic. I can compare them directly without worrying if one was tested more rigorously than the other.




📋 Practical Task

Predicting Wine Quality with Model Comparison

Using the wine dataset from the rattle package (or any classification dataset of your choice), build two competing models using caret to predict the wine's quality or class.

  • Create a trainControl object that implements 5-fold cross-validation.
  • Train a Random Forest model (method = "rf").
  • Train a Support Vector Machine model (method = "svmRadial").
  • Use the print() function on both model objects to identify which algorithm achieved the higher accuracy.
  • Bonus: Add preProcess = c("center", "scale") to your SVM model and observe if it improves the results.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.