Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 52

`assertthat` for Data Validation

Recommended resources

In our last lesson, we focused on interpreting confidence intervals, a crucial concept for understanding the precision of our statistical estimates. We've now built a solid foundation for exploring and describing data, from checking distributions to quantifying relationships and uncertainty. This lesson marks a transition from exploration to validation, introducing a tool that ensures the quality and integrity of your data before you begin formal statistical testing.

Your goal is to produce high-quality data analysis for clinical research, where mistakes can have serious consequences. A common but dangerous issue in any programming is the "silent failure"—code that runs without error but produces an incorrect result because the input data violated a hidden assumption. This lesson tackles that problem head-on by teaching you how to use assertions: statements that check if your assumptions about the data are true and stop your analysis with a clear error message if they are not.

Specifically, we will cover how to use the assertthat package and its main function, assert_that(), to build robust, defensive checks into your R code. This practice is a cornerstone of professional, reproducible data analysis.

1. The Problem: The Danger of Silent Failures

As you begin to write more complex analysis scripts and functions, you'll be making implicit assumptions about your data at every step. For example, you might assume that a column of patient weights contains only positive numbers, that a patient ID is always unique, or that a specific variable has no missing values. What happens when these assumptions are wrong? Often, R will not produce an error. Instead, it might return NA, NaN, or a nonsensical value that silently corrupts the rest of your analysis.

This is a universal problem in data analysis. The following blog post provides a perfect, and quite witty, introduction to why this is such a critical issue.

Four ways to write assertion checks in R – Notes from a data witch

This post by data scientist Danielle Navarro captures the "problem-first" motivation for using assertions.

Read the introduction, from the beginning down to the sentence "So. Let's talk about...". The author's description of becoming an "embittered old data analyst" perfectly illustrates why trusting your data (or your own code) without verification is a risky habit.

The key takeaway is that you want your code to "fail fast and fail loudly" as soon as an assumption is violated. This prevents you from wasting time debugging a mysterious result downstream or, even worse, reporting an incorrect finding.


2. The Solution: What is an Assertion?

An assertion is a piece of code that declares a condition must be true at a particular point in your program. If the condition is true, nothing happens, and the program continues. If the condition is false, the program immediately halts and throws an error.

Assertions are a tool for the programmer. They are used to catch bugs and validate assumptions during development and analysis, rather than to handle predictable user errors (like a user typing text where a number is expected in an application).

The resource below, from a course on statistical computing, provides a concise, formal definition of what assertions are for.

Assertions

This resource explains the role of assertions in robust programming.

First, read the section "What are assertions for?" to understand their primary purpose. Then, see the confirmation that for R, the assertthat package is a common choice and that it is often used for checking function inputs, which is exactly how we'll be using it.


3. Implementing Assertions with assertthat

While base R has a function called stopifnot() for creating assertions, it can be a bit clunky, especially when it comes to producing clear, helpful error messages. The assertthat package, created by Hadley Wickham, is designed to be a more user-friendly and expressive tool for the same purpose.

The main function is assert_that(). Its basic structure is:
assert_that(condition, msg = "Your custom error message here")

  • The condition is an expression that should evaluate to TRUE.
  • The msg argument is optional, but it's where the power of assertthat lies. It allows you to provide a clear, human-readable error message that explains exactly what assumption was violated.

The blog post you read earlier gives an excellent demonstration of how assertthat improves upon base R and leads to more readable code.

Four ways to write assertion checks in R – Notes from a data witch

This section provides a side-by-side comparison that makes the value of assertthat clear.

Read the section "Just assert_that(), Kat". Pay close attention to the code example. Notice how the author groups related checks into a single assert_that() call, with each group having its own tailored error message. This makes the code much cleaner and the errors far more informative than the stopifnot() example that precedes it. Also, review the short summary paragraph that follows.


4. Assertions in a Clinical Data Context

Let's apply this to a realistic scenario. Imagine you have a dataset of patient information and you want to calculate the Body Mass Index (BMI). The formula is .

Before you perform this calculation, you should assert that your data meets the necessary conditions. Let's create a sample dataset with some deliberate errors.

# First, make sure you have the necessary packages installed and loaded
# install.packages("dplyr")
# install.packages("assertthat")
library(dplyr)
library(assertthat)

# A sample patient dataset with errors
patient_data <- tibble(
  patient_id = c("P01", "P02", "P03", "P04", "P05"),
  weight_kg = c(75, 82, 58, NA, 67),      # Contains a missing value
  height_m = c(1.80, 1.85, 1.62, 1.70, -1.75) # Contains a negative value
)

Now, let's write some assertions to validate this data before we attempt the BMI calculation. The assertthat package includes several helpful "flag" functions that make writing conditions easier, such as has_name() and noNA().

# 1. Assert that the required columns exist
assert_that(has_name(patient_data, "weight_kg"), msg = "Data is missing the 'weight_kg' column.")
assert_that(has_name(patient_data, "height_m"), msg = "Data is missing the 'height_m' column.")

# 2. Assert that the columns are numeric
assert_that(is.numeric(patient_data$weight_kg), msg = "'weight_kg' must be a numeric column.")
assert_that(is.numeric(patient_data$height_m), msg = "'height_m' must be a numeric column.")

# 3. Assert that there are no impossible values (e.g., negative height/weight)
# The `all()` function checks if every element meets the condition.
assert_that(all(patient_data$height_m > 0, na.rm = TRUE), msg = "All 'height_m' values must be positive.")

If you run the code above, the first two sets of assertions will pass. However, the third assertion will fail and stop your script with the following error:

Error: All 'height_m' values must be positive.

This is exactly what we want! The script stops immediately, and the message tells you precisely what's wrong. Now, let's try an assertion that checks for missing values.

# 4. Assert that there are no missing values in the columns we need
assert_that(noNA(patient_data$weight_kg), msg = "Missing values detected in 'weight_kg'.")

Running this line will produce the error:

Error: Missing values detected in 'weight_kg'.

By placing these checks at the beginning of your script or at the start of a function, you create a "gatekeeper" that ensures your data is clean and valid before any analysis is performed. This simple habit will save you countless hours of debugging and dramatically increase the reliability of your research findings.


Conclusion

In this lesson, you've added a powerful defensive programming technique to your toolkit. You've learned how to move from hoping your data is correct to programmatically guaranteeing that it meets your expectations.

Key Takeaways:

  • Silent failures are a significant risk in data analysis, where code can produce incorrect results without warning.
  • Assertions are statements that check for conditions that must be true, halting execution with an error if the condition is false. This is the "fail fast, fail loudly" principle.
  • The assertthat package provides the user-friendly assert_that() function for implementing assertions in R.
  • Using assert_that(condition, msg = "...") allows you to write clear, custom error messages that make debugging simple and efficient.
  • Incorporating assertions into your analysis scripts is a key practice for producing robust, reliable, and professional-grade work, which is essential in fields like clinical research.

Preview of the Next Lesson:
With our tour of descriptive statistics, data exploration, and now data validation complete, we are fully prepared to begin formal statistical testing. In our next lesson, we will dive into the workhorse of hypothesis testing: the t-test. You will learn how to perform and interpret one-sample, independent two-sample, and paired t-tests in R to compare mean values between groups.