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
127: Non-Standard Evaluation in R
If you've spent any time with the tidyverse, you've already been using Non-Standard Evaluation (NSE) without realizing it. When you write filter(df, species == "Setosa"), you aren't passing a string or a variable called species; you're passing the symbol species, and filter is smart enough to look for that symbol inside the columns of df. It's a bit of R magic that makes code read like a sentence, but the moment you try to wrap that logic inside your own function, the magic usually breaks.
The "Column Not Found" Trap
I see this mistake constantly when people start writing helper functions. Let's say you want a function that filters a dataset based on a column name and a specific value. Your first instinct is probably to do something like this:
# This will not work as you expect
filter_by_value <- function(data, col_name, value) {
dplyr::filter(data, col_name == value)
}
mtcars %>% filter_by_value("cyl", 6)
You'll likely get an error saying column 'col_name' not found. Here is why: filter() is designed for NSE. It expects a bare column name. When you pass col_name into the function, R looks at the expression col_name == value and thinks you are literally looking for a column named "col_name" in your data frame. It doesn't realize that col_name is actually a variable holding the string "cyl".
You might try to "fix" this using the old-school eval(parse(text = ...)) approach. I'll be honest: don't do that. It's a security nightmare, it's slow, and it's incredibly difficult to debug. You're essentially treating your code as a string and asking R to execute it, which is a recipe for disaster in any professional pipeline.
Quoting and Unquoting with Curly-Curly
The modern, "Tidy" way to handle this is through a process called "embedding." We want to tell R: "Don't evaluate this argument right now; wait until you're inside the filter call, and then treat it as a column name."
In recent versions of rlang and dplyr, we use the {{ }} (curly-curly) operator. It acts as a bridge between the standard evaluation of your function arguments and the non-standard evaluation of the dplyr verb.
# The professional way
filter_by_value <- function(data, col_name, value) {
dplyr::filter(data, {{ col_name }} == value)
}
# Now we pass the column name WITHOUT quotes
mtcars %>% filter_by_value(cyl, 6)
Notice the subtle change in how the function is called. We no longer pass "cyl" as a string; we pass cyl as a symbol. The {{ }} operator captures that symbol and "unquotes" it into the filter call. It's cleaner, it's type-safe, and it maintains the declarative style that makes R powerful for data analysis.
The Trade-off: Flexibility vs. Predictability
So, why not use NSE for everything? Because NSE adds a layer of cognitive load. When you use {{ }}, you are explicitly changing the rules of how R evaluates code. If you're building a package for other developers, they might be confused why your function expects an unquoted symbol instead of a standard character string.
If you absolutely must accept a string (for example, if the column name is coming from a JSON API or a user-input text box), {{ }} won't work because the input is already a string, not a symbol. In those cases, you'd use .data[[col_name]]. I prefer curly-curly for internal analysis scripts because it feels native to the tidyverse, but I lean toward the .data pronoun when building robust production tools. It's a trade-off between "elegant syntax" and "explicit behavior."
📋 Practical Task
Building a Dynamic Column Summarizer
You need to create a helper function called summarize_column that takes a data frame and a column name, and returns the mean of that column. However, the function must be written using Non-Standard Evaluation (the curly-curly operator) so that the user can pass the column name without quotes.
Requirements:
- The function should take two arguments:
dataandtarget_col. - Inside the function, use
dplyr::summarize()andmean(..., na.rm = TRUE). - Ensure the result is a data frame containing the mean.
- Test your function using the
irisdataset, calculating the mean of theSepal.Lengthcolumn without putting the column name in quotes.
There are no comments for now.