Machine Learning with caret

Reviewed & published by Brayan K

caret gives you a single, consistent interface to hundreds of machine-learning algorithms in R — handling data splitting, preprocessing, resampling, tuning, and evaluation through one workflow.

Part of the free R course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

By the end of this lesson you'll split data with createDataPartition(), fit and tune models with train() and trainControl(), and score them with confusionMatrix().

What You'll Learn in This Lesson

1️⃣ Splitting Data with createDataPartition()

Before modelling, hold out a test set the model never sees. createDataPartition() makes a stratified split, keeping each class's proportion balanced across train and test.

library(caret)

# createDataPartition makes a STRATIFIED train/test split so the
# outcome's class balance is preserved in both halves.
set.seed(42)
data(iris)

idx   <- createDataPartition(iris$Species, p = 0.8, list = FALSE)
train <- iris[idx, ]
test  <- iris[-idx, ]

nrow(train)   # -> [1] 120
nrow(test)    # -> [1] 30

2️⃣ Fitting with train() and trainControl()

trainControl() says how to resample (here, 5-fold cross-validation); train() does the fitting and reports resampled accuracy. preProcess standardizes predictors first.

library(caret)

# trainControl() defines HOW we resample; train() does the fitting + tuning.
ctrl <- trainControl(method = "cv", number = 5)   # 5-fold cross-validation

set.seed(42)
model <- train(
  Species ~ .,          # formula: predict Species from all other columns
  data       = train,
  method     = "rpart", # a decision tree
  trControl  = ctrl,
  preProcess = c("center", "scale")  # standardize predictors
)

model   # prints accuracy across the tried complexity values (cp)

3️⃣ Tuning Hyperparameters

A tuneGrid lists candidate hyperparameter values. train() fits every combination under the resampling scheme and keeps the best in $bestTune.

library(caret)

# A tuning grid lists the hyperparameter values to try.
# For a k-nearest-neighbours model we tune k.
grid <- expand.grid(k = c(3, 5, 7, 9))

ctrl <- trainControl(method = "cv", number = 5)
set.seed(42)
knn_fit <- train(
  Species ~ .,
  data      = train,
  method    = "knn",
  trControl = ctrl,
  tuneGrid  = grid
)

knn_fit$bestTune    # the k caret selected -> e.g. k = 7

4️⃣ Evaluating with confusionMatrix()

predict() applies the trained model to the held-out test set, and confusionMatrix() reports accuracy, sensitivity, specificity, and kappa.

library(caret)

# predict() applies the model, confusionMatrix() scores it on held-out test data.
preds <- predict(model, newdata = test)
confusionMatrix(preds, test$Species)
#   Accuracy : 0.9667
#   Sensitivity / Specificity reported per class

Your turn. Fill in the ___ blank, run it, and compare with the expected output.

library(caret)

# 🎯 YOUR TURN — replace each ___ then run it.

set.seed(1)
data(iris)
idx   <- createDataPartition(iris$Species, p = 0.7, list = FALSE)
train <- iris[idx, ]
test  <- iris[-idx, ]

# 1) Use 10-fold cross-validation
ctrl <- trainControl(method = "cv", number = ___)   # 👉 replace ___ with 10

# 2) Train a tree (method = "rpart") to predict Species
model <- train(Species ~ ., data = train, method = "rpart", trControl = ctrl)

# 3) Score it on the test set
preds <- predict(model, newdata = test)
confusionMatrix(preds, test$Species)$overall["Accuracy"]

# ✅ Expected: an accuracy near 0.93 (your exact number may vary slightly)

Mini-Challenge: Compare Two Models

Train a kNN and a tree on the same split, then compare their test accuracies. Swapping methods while keeping everything else fixed is exactly what caret makes painless.

# 🎯 MINI-CHALLENGE: compare two models.
#
# Using the iris train/test split:
# 1. trainControl() with method = "cv", number = 5.
# 2. Train a kNN model (method = "knn") and an rpart tree.
# 3. predict() each on the test set.
# 4. Print both accuracies with confusionMatrix(...)$overall["Accuracy"].
#
# ✅ Example output:
#    kNN accuracy:   0.9778
#    Tree accuracy:  0.9556

# your code here

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — caret

TaskR Syntax
Train/test splitcreateDataPartition(y, p = 0.8, list = FALSE)
Resampling controltrainControl(method = "cv", number = 10)
Fit a modeltrain(y ~ ., data, method, trControl)
Tune gridtuneGrid = expand.grid(k = c(3, 5, 7))
Predictpredict(model, newdata)
EvaluateconfusionMatrix(preds, truth)

🎉 Lesson Complete!

Practice quiz

What is the main function in caret for fitting a model?

  • train()
  • model()
  • learn()
  • fit()

Answer: train(). train() is caret's unified interface for fitting and tuning hundreds of model types.

Which caret function sets resampling and control options for train()?

  • resample()
  • tuneControl()
  • trainControl()
  • controlSet()

Answer: trainControl(). trainControl() configures the resampling method, number of folds, and other control settings.

What does createDataPartition() do?

  • Creates new columns
  • Splits data into train/test with balanced outcome classes
  • Deletes missing rows
  • Centers and scales predictors

Answer: Splits data into train/test with balanced outcome classes. createDataPartition() makes a stratified train/test split so class proportions are preserved.

Which preProcess steps standardize predictors in caret?

  • log and exp
  • sort and filter
  • merge and join
  • center and scale

Answer: center and scale. preProcess = c('center', 'scale') subtracts the mean and divides by the standard deviation.

What does the tuneGrid argument to train() control?

  • The candidate hyperparameter values to try
  • The number of CPU cores
  • The random seed only
  • The plotting theme

Answer: The candidate hyperparameter values to try. tuneGrid supplies a data frame of hyperparameter combinations caret evaluates during tuning.

What does confusionMatrix() report for a classifier?

  • A correlation matrix
  • Accuracy, sensitivity, specificity and related metrics
  • The model coefficients
  • Only the accuracy

Answer: Accuracy, sensitivity, specificity and related metrics. confusionMatrix() cross-tabulates predictions vs truth and computes accuracy, sensitivity, specificity, kappa, and more.

In trainControl(method = 'cv', number = 10), what does number specify?

  • The number of trees
  • The number of repeats
  • The number of predictors
  • The number of cross-validation folds

Answer: The number of cross-validation folds. With method = 'cv', number is the count of folds, so 10 means 10-fold cross-validation.

How do you generate predictions from a trained caret model?

  • output(model)
  • guess(model)
  • predict(model, newdata)
  • forecast(model)

Answer: predict(model, newdata). predict() applies the fitted model to newdata to return class labels or probabilities.

Which of these is a modern alternative framework to caret?

  • lubridate
  • tidymodels
  • ggplot2
  • knitr

Answer: tidymodels. tidymodels (and mlr3) are modern successors to caret for modeling workflows in R.

Why does caret resample during training?

  • To estimate out-of-sample performance and pick hyperparameters
  • To remove all NA values
  • To convert factors to numbers
  • To shuffle column order

Answer: To estimate out-of-sample performance and pick hyperparameters. Resampling like cross-validation estimates how the model generalizes and guides hyperparameter selection.

Continue this course

Frequently asked questions

What is caret and what problem does it solve?

caret (Classification And REgression Training) is a wrapper package that gives you one consistent interface to hundreds of modelling algorithms in R. Instead of learning a different function signature for every algorithm, you call train() with a method name. caret also standardizes the surrounding workflow: data splitting, preprocessing, resampling, hyperparameter tuning, and evaluation. That uniformity is what makes it easy to swap a decision tree for a random forest and compare them fairly.

What is the difference between trainControl() and tuneGrid?

trainControl() configures HOW the model is validated — the resampling method (cross-validation, bootstrap, repeated CV), the number of folds, and options like saving predictions. tuneGrid configures WHAT hyperparameters to try — it is a data frame whose columns are the tunable parameters of the chosen method and whose rows are the candidate combinations. train() fits the model for every grid row under the resampling scheme from trainControl(), then keeps the combination with the best resampled performance.

Why split data and use cross-validation instead of fitting on everything?

A model evaluated on the same data it was trained on will look better than it really is, because it can memorize noise. createDataPartition() holds out a test set the model never sees, giving an honest final score. Cross-validation goes further during training: it repeatedly trains on most of the data and validates on the rest, so the performance estimate and the hyperparameter choice are based on out-of-sample behaviour. Together they guard against overfitting.

Is caret still the right choice, or should I use tidymodels?

caret is mature, stable, and widely used, so it remains a solid choice and is well documented. However, its author has shifted active development to tidymodels, a tidyverse-aligned collection (recipes, parsnip, rsample, yardstick, tune) that is more modular and composes with the pipe. mlr3 is another modern, object-oriented framework. For new projects many people now learn tidymodels, but the concepts you learn here — splitting, resampling, tuning, evaluating — transfer directly to any of them.