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
240: Practice Exercise: Merging Multiple Messy Data Sources
I've spent more hours than I'd like to admit staring at a dataframe that should have 1,000 rows after a join, only to find it has zero. When you're merging messy data sources—especially when those sources come from different departments or legacy systems—the code usually looks correct, but the data is lying to you.
Take a look at this snippet. I'm trying to merge a customer list with their recent purchase history using left_join from dplyr.
# The setup
customers <- data.frame(cust_id = c("C101", "C102", "C103"), name = c("Alice", "Bob", "Charlie"))
purchases <- data.frame(customer_id = c("c101", "C102 ", "C103"), amount = c(50, 100, 150))
# The join
merged_data <- customers %>%
left_join(purchases, by = c("cust_id" = "customer_id"))
print(merged_data)
# Result: Alice has NA, Bob has NA, Charlie has 150.
# Wait... why did Alice and Bob disappear?
The Invisible Character Trap
If you look closely at the purchases dataframe, you'll see the culprit. Alice's ID is lowercase ("c101") and Bob's ID has a trailing space ("C102 "). To R, these are entirely different strings. This is the most common "bug" when merging messy sources: the keys look identical to the human eye, but they are mathematically different.
When this happens, don't just guess. I always use an anti_join to see exactly which rows are failing to match. It's the fastest way to diagnose the mismatch.
# Diagnosing the gap
mismatches <- customers %>%
anti_join(purchases, by = c("cust_id" = "customer_id"))
print(mismatches)
# This shows us Alice and Bob are the ones not matching.
Sanitizing Keys Before the Merge
The fix isn't to manually edit the CSV files. You need to build a "cleaning pipeline" that standardizes your keys before they ever hit the join function. I typically use stringr for this because it's explicit and readable.
library(dplyr)
library(stringr)
# Clean both sources to a common standard: trimmed and uppercase
clean_customers <- customers %>%
mutate(cust_id = str_trim(str_to_upper(cust_id)))
clean_purchases <- purchases %>%
mutate(customer_id = str_trim(str_to_upper(customer_id)))
# Now the join actually works
merged_data <- clean_customers %>%
left_join(clean_purchases, by = c("cust_id" = "customer_id"))
Scaling to Multiple Messy Files
In the real world, you aren't usually merging two dataframes; you're merging twenty. Writing twenty left_join statements is a recipe for a copy-paste error. Instead, I use purrr::reduce. It allows you to take a list of dataframes and "collapse" them into one using a specific function.
The trick here is ensuring every single dataframe in your list has the key column named identically. If one is called cust_id and another is CustomerID, reduce will fail. I recommend a quick rename step inside a map call before you start the reduction process.
library(purrr)
# Imagine a list of 5 messy dataframes
all_dfs <- list(df1, df2, df3, df4, df5)
# 1. Standardize column names and clean keys across all DFs
standardized_dfs <- all_dfs %>%
map(~ .x %>%
rename(join_key = 1) %>% # Assume the first column is always the key
mutate(join_key = str_trim(str_to_upper(join_key))))
# 2. Reduce them all into one master dataframe
final_df <- standardized_dfs %>%
reduce(full_join, by = "join_key")
By using full_join here, I ensure that I don't lose any data from any of the sources, even if some customers only appear in the fifth file. I can always filter out the NA rows later if they aren't needed.
📋 Practical Task
Exercise: Consolidating Fragmented Q3 Regional Sales Reports
You have been handed three different dataframes representing sales from three different regions. Each is "messy" in its own way: some have inconsistent casing, some have leading/trailing whitespace, and the ID columns have different names.
The Data:
north_sales <- data.frame(id = c("A101", "A102", "A103"), revenue = c(1000, 1500, 1200))
south_sales <- data.frame(SaleID = c("a101 ", "A102", "A104"), revenue = c(800, 900, 1100))
east_sales <- data.frame(ClientID = c("A101", " a103", "A105"), revenue = c(700, 600, 1300))
Your Task:
- Create a list containing these three dataframes.
- Use a
mapfunction to rename the ID column in each dataframe tostandard_idand clean the values (remove whitespace and convert to uppercase). - Use
reducewith afull_jointo merge all three datasets into one master dataframe calledmaster_sales. - Verify that
master_salescontains 5 unique IDs (A101 through A105).
There are no comments for now.