-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Data Structures
-
Section 4: Data Manipulation
-
Section 5: Visualization and Statistics
-
Section 6: Advanced R
-
Section 7: Practical Projects
-
Section 8: Interview Practice
-
Section 9: More Practice Exercises
-
Section 10: Shiny Apps in Depth
-
Section 11: More Data Wrangling
-
Section 12: Tidyverse Deep Dive
-
Section 13: Statistical Modeling Deep Dive
-
Section 14: Machine Learning in R
-
Section 15: R Visualization Deep Dive
-
Section 16: R Package Development Deep Dive
-
Section 17: R for Reproducible Research
-
Section 18: R and Databases
-
Section 19: R Performance Optimization
-
Section 20: Bioinformatics and Specialized R
-
Section 21: More Shiny Practice
-
Section 22: More Practice Exercises
-
Section 23: R Data Structures Deep Dive
-
Section 24: More Interview and Review
-
Section 25: R for Business Analytics
-
Section 26: R Text Mining and NLP
-
Section 27: R Spatial Data Analysis
-
Section 28: R Deep Learning
-
Section 29: Advanced Statistical Techniques
-
Section 30: R Object Systems Deep Dive
-
Section 31: R Environments and Metaprogramming
-
Section 32: R for Finance
-
Section 33: R for Clinical and Health Data
-
Section 34: More Shiny Advanced Practice
-
Section 35: R Data Cleaning Deep Dive
-
Section 36: R Reporting Automation
-
Section 37: More Practical Projects Round 2
-
Section 38: R Ecosystem and Career
-
Section 39: More Visualization Practice
-
Section 40: R for Experimentation
-
Section 41: R for Genomics and Bioinformatics Deep Dive
-
Section 42: R for Marketing Analytics
-
Section 43: R Data Import/Export Deep Dive
-
Section 44: R String Processing Deep Dive
-
Section 45: R for Actuarial and Insurance Analytics
-
Section 46: R Testing and Quality Assurance Deep Dive
-
Section 47: R Version Control and Collaboration
-
Section 48: R Advanced Functional Programming
-
Section 49: R for Supply Chain and Operations
-
Section 50: More Practice Exercises Round 3
-
Section 51: R Dashboards and BI Integration
-
Section 52: R Data Governance and Ethics
-
Section 53: More Modeling Practice
-
Section 54: R Final Capstone Projects
-
Section 55: R for Sports Analytics
-
Section 56: More Interview Practice Round 2
-
Section 57: R Networking and APIs
-
Section 58: R for Environmental Science
-
Section 59: R Notebook and Documentation Practices
-
Section 60: More Data Wrangling Mastery
-
Section 61: R for A/B Testing at Scale
-
Section 62: R Package Ecosystem Deep Dive
92: Practice Exercise: Building a Predictive Model with tidymodels
Alright, we've talked about the theory of the tidymodels ecosystem, but it's one thing to read the documentation and another to actually get a model to behave. Let's get our hands dirty. I'm going to use the palmerpenguins dataset. The goal is simple: can we predict the species of a penguin based on its bill length, bill depth, and flipper length?
Getting the data split just right
First, I'll start by splitting the data. I've seen too many people just take the first 80% of a CSV, which is a disaster if the data is sorted. I'll use initial_split().
library(tidymodels)
library(palmerpenguins)
set.seed(123)
penguin_split <- initial_split(penguins, prop = 0.8, strata = species)
train_data <- training(penguin_split)
test_data < - testing(penguin_split)
Notice I added strata = species. I did this because I don't want to accidentally end up with a test set that has zero Gentoo penguins. Stratification ensures the proportions of species stay the same across both sets. If I didn't do this, my accuracy metrics might look great or terrible just because of a lucky (or unlucky) draw.
Cleaning up the inputs with a recipe
Now, I could just throw the train_data into a model, but that's a bad habit. In a real project, you'll have missing values or need to normalize scales. I'll build a recipe. Let's see what happens if I just keep it basic.
penguin_recipe < - recipe(species ~ ., data = train_data) >
step_naomit(all_predictors())
Wait, I just realized something. If I use step_naomit() inside a recipe, it can get a bit finicky with how tidymodels handles the data flow. Actually, for this specific dataset, it's cleaner to just filter out the NAs from the original dataframe before the split. I'm adjusting my approach—lesson learned: handle the "hard" removals before the tidymodels pipeline starts, and use the recipe for "soft" transformations.
# Redoing the split after cleaning penguins_clean < - penguins |> drop_na() set.seed(123) penguin_split < - initial_split(penguins_clean, prop = 0.8, strata = species) train_data < - training(penguin_split) test_data < - testing(penguin_split) penguin_recipe < - recipe(species ~ ., data = train_data) > step_normalize(all_numeric_predictors())I added
step_normalize()because while Random Forests don't strictly need it, I'm in the habit of doing it. It makes the model more robust if I decide to swap the engine to something like a Support Vector Machine later.Picking a model and hitting a snag
I want to use a Random Forest. I'll define the model specification first.
rf_spec < - rand_forest(trees = 100)Now, if I try to
fit()this right now, R is going to scream at me. Why? Becauserand_forest()is just a specification—it's like a blueprint. It doesn't actually know which R package should do the heavy lifting. I need to set the engine. I'll userangerbecause it's fast.rf_spec < - rf_spec |> set_engine("ranger") |> set_mode("classification")I explicitly set the mode to "classification" because we are predicting a category (species), not a number. If I forget this, tidymodels might try to guess based on the data, but being explicit saves me from a headache three hours into a project.
Wiring it all together
Now for the "magic" part: the workflow. Instead of managing the recipe and the model separately, I'll bundle them. This prevents the common mistake of applying a transformation to the test set that wasn't applied to the training set (data leakage).
penguin_wf < - workflow() |> add_recipe(penguin_recipe) |> add_model(rf_spec) # Fit the model penguin_fit < - fit(penguin_wf, data = train_data)Finally, let's see how we actually did. I'll use
augment()to add predictions to my test data and then check the accuracy.results < - augment(penguin_fit, new_data = test_data) results |> metrics(truth = species, estimate = .pred_class)Looking at the output, the accuracy is likely near 98-100%. This dataset is almost "too" easy, but the pipeline is now solid. If I wanted to try a different model, I'd only have to change the
rf_specpart and re-run the workflow. That's the real power of this approach.
📋 Practical Task
Exercise: Predicting Diamond Quality
Using the diamonds dataset (built into ggplot2), build a predictive model to classify the cut of a diamond based on its physical attributes (carat, cut, color, clarity, depth, table, price, x, y, z).
Your task is to implement the following pipeline using tidymodels:
- Data Preparation: Split the
diamondsdataset into training (75%) and testing (25%) sets, stratifying by thecutvariable. - The Recipe: Create a recipe that predicts
cut. Include a step to normalize all numeric predictors. - The Model: Define a Decision Tree model (
decision_tree()) using therpartengine. Set the mode to "classification". - The Workflow: Combine the recipe and model into a workflow and fit it using the training data.
- Evaluation: Use
augment()on the test set and calculate the accuracy and Kappa metrics.
Deliverable: A script that outputs the final accuracy of the diamond cut prediction model.
There are no comments for now.