R
Completed
-
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
46: Working with purrr for Functional Iteration
Why bother with purrr when I can just use a for loop?
I get this question a lot. Look, for loops aren't "wrong," but in R, they're often clunky. You have to pre-allocate a vector or a list to hold your results, manage an index variable, and write a lot of boilerplate code just to do something simple. It's a lot of surface area for bugs to hide in.
purrr gives us a consistent set of tools for "functional iteration." Instead of telling R how to loop (increment i, check length, assign to index), you tell it what to do to every element in a collection. It's cleaner, it's more readable, and it plays beautifully with the pipe operator. Once you get used to the map family of functions, going back to for loops feels like writing assembly language when you have a high-level language available.
What's with the tilde (~) and the .x syntax?
If you've looked at purrr code, you've probably seen things like map(data, ~ .x * 2). This is just "syntactic sugar" for creating an anonymous function. In base R, you'd have to write map(data, function(x) { x * 2 }). That's a lot of typing for a simple operation.
The tilde ~ tells purrr: "Everything following this is a formula that should be treated as a function." The .x is a placeholder for "the current item being processed." If you're mapping over two lists simultaneously using map2, you'll see .x and .y.
# The long way
results <- map(my_list, function(x) {
mean(x, na.rm = TRUE)
})
# The purrr way (much faster to write)
results <- map(my_list, ~ mean(.x, na.rm = TRUE))
How do I avoid getting a list of lists back?
The standard map() always returns a list. That's great for flexibility, but it's a nightmare when you actually want a vector of numbers or a single data frame. This is where the "type-specific" map functions come in. I almost always use these instead of the generic map() because they enforce type stability.
If you want a numeric vector, use map_dbl(). If you want a character vector, map_chr(). But the real superpower is map_df(). It takes the result of each iteration (which should be a data frame) and stacks them all on top of each other into one big tibble. This is how I handle the "read 50 CSV files and combine them" problem in about two lines of code:
library(purrr)
library(readr)
files <- list.files(path = "data/monthly_reports", full.names = TRUE)
# Instead of a loop and rbind(), just do this:
all_data <- map_df(files, read_csv)
Is there a way to iterate just to "do something" without returning data?
Sometimes you don't want a result. Maybe you're saving a plot to a folder for every city in a dataset, or sending an email to a list of clients. If you use map() for this, R will dutifully return a massive list of NULL values or empty outputs, which just clutters your console.
For these "side effects," use walk(). It's identical to map() in terms of how it works, but it returns the original input invisibly. It's a signal to anyone reading your code that "I'm doing this for the side effect, not to transform the data."
# Saving a plot for each category
categories <- c("Electronics", "Clothing", "Home")
walk(categories, ~ {
p <- ggplot(df, aes(x, y)) + filter(category == .x)
ggsave(filename = paste0("plot_", .x, ".png"), plot = p)
})
# No giant list of NULLs printed to the screen!
📋 Practical Task
Exercise: Processing Regional Sales Logs
You have been given a list of file paths to three CSV files, each containing sales data for a different region. Your goal is to read these files and calculate the total revenue for each region, returning the results as a named numeric vector.
Setup: Run this code first to create the dummy files in your environment:
dir.create("sales_data", showWarnings = FALSE)
write.csv(data.frame(item="A", price=10, qty=2), "sales_data/north.csv", row.names=FALSE)
write.csv(data.frame(item="B", price=20, qty=1), "sales_data/south.csv", row.names=FALSE)
write.csv(data.frame(item="C", price=15, qty=3), "sales_data/east.csv", row.names=FALSE)
file_paths <- list.files("sales_data", full.names = TRUE)
names(file_paths) <- c("North", "South", "East")
Your Task: Use purrr::map_dbl() to iterate over file_paths. Inside the map function, read the CSV and calculate the total revenue (price * qty) for that file. The final output should be a numeric vector where the names are the regions and the values are the totals.
There are no comments for now.