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
249: Contributing Fixes to Existing R Packages
Most of your time as an R developer won't be spent writing packages from scratch; it'll be spent using other people's packages and eventually hitting a wall where a function doesn't do what the documentation claims it does. When that happens, you have two choices: write a wrapper to hide the bug, or actually fix the source. I always lean toward the latter. It's cleaner, and it earns you some respect in the community.
Pinpointing the failure
Let's say we're using a hypothetical utility package called textutils. It has a function called trim_and_cap() that is supposed to trim whitespace and capitalize the first letter of a string. It works great for single strings, but I noticed it crashes when I pass it a character vector containing an NA.
# This works fine
textutils::trim_and_cap(" hello")
# [1] "Hello"
# This throws an error or returns unexpected results
textutils::trim_and_cap(c(" hello", NA))
# Error in trim_and_cap: argument is not a character string
Before I even touch the source code, I need a Minimal Reproducible Example (MRE). If I can't reproduce the bug in three lines of code, I can't be sure I've fixed it later. The snippet above is my MRE.
Setting up the workspace
I don't just edit the package in my site-library—that's a recipe for disaster. Instead, I fork the repository on GitHub and clone it locally. I'll use devtools to load the package in a way that lets me edit the functions in real-time.
# Clone the repo and open the project in RStudio
# Then, load the package for development
devtools::load_all()
By using load_all(), I'm essentially simulating the package being installed, but any changes I make to the R/ directory are immediately available in my global environment.
The "quick fix" mistake
I dig into the source code for trim_and_cap() and see this:
trim_and_cap <- function(x) {
x <- trimws(x)
paste0(toupper(substr(x, 1, 1)), substr(x, 2, nchar(x)))
}
The issue is that substr() handles NAs okay, but the overall logic isn't explicitly guarding against them in a way that plays nice with the paste0 call. I'll try a quick fix by adding a simple if check to skip NA values.
# My first (wrong) attempt
trim_and_cap <- function(x) {
if (is.na(x)) return(NA)
x <- trimws(x)
paste0(toupper(substr(x, 1, 1)), substr(x, 2, nchar(x)))
}
I run my MRE again, and R screams at me: Warning message: the condition has length > 1 and only the first element will be used. I forgot the golden rule of R: vectorization. if() only checks a single logical value. Since I'm passing a vector c(" hello", NA), is.na(x) returns a logical vector, and the if statement chokes.
Correcting for vectorization
I need to handle the NAs without breaking the vector. I could use a loop, but that's slow and un-idiomatic. Instead, I'll use ifelse() or just let the natural vectorization of substr and toupper do the work, while ensuring I'm not accidentally introducing "NA" (the string) where I want NA (the logical constant).
Actually, the cleanest way here is to just let R's vectorization happen and ensure the substr doesn't create weird artifacts. Let's try this approach:
trim_and_cap <- function(x) {
x <- trimws(x)
# We use vapply or a vectorized approach to ensure we keep NA as NA
res <- paste0(toupper(substr(x, 1, 1)), substr(x, 2, nchar(x)))
# Ensure that original NAs remain NAs
res[is.na(x)] <- NA
return(res)
}
Now I run my MRE again. It works perfectly. I've preserved the vector length and handled the missing values without triggering any warnings.
Finalizing the contribution
Before I submit the Pull Request, I run devtools::test() to make sure I haven't accidentally broken something else in the package. This is where most "fix" PRs get rejected—the contributor fixes one bug but breaks three existing features. Once the tests pass, I commit my changes with a clear message: "Fix: handle NA values in trim_and_cap to prevent crash".
📋 Practical Task
Fixing the Vectorization Bug in calculate_growth()
You are contributing to a package called econtools. The function calculate_growth() is designed to calculate the percentage growth between two numeric vectors. However, it currently fails when the input vectors contain NA values because it uses a non-vectorized if check.
Current broken code:
calculate_growth <- function(old, new) {
if (is.na(old) || is.na(new)) {
return(NA)
}
return((new - old) / old)
}
Your Task:
- Identify why
calculate_growth(c(10, 20), c(12, NA))triggers a warning and fails to return a full vector. - Rewrite the function to be properly vectorized. It should return a numeric vector of the same length as the inputs, where any element involving an
NAremainsNA. - Ensure your solution does not use a
forloop.
There are no comments for now.