Skip to Content
Course content

141: Data Validation with the validate Package

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Think of data validation like a customs officer at an international airport. The officer doesn't just look at a traveler and say, "Something feels wrong here." Instead, they have a very specific checklist: Is the passport valid? Is the visa stamped? Are there any prohibited items in the suitcase? If a traveler fails, the officer doesn't just throw the whole person away; they mark exactly which requirement wasn't met. This allows the traveler to fix the specific issue and move forward.

In R, the validate package does exactly this for your dataframes. Instead of writing a sprawling mess of if statements or using stopifnot()—which just crashes your script the moment it hits the first error—validate lets you define a "checklist" of rules and then run your data against them to see exactly where the cracks are.

Defining Your Quality Checklist

I've spent way too many hours debugging models only to realize my "Age" column had a few values of -5 and 200. To prevent that, we use the validator() function. This is where you describe what "correct" looks like. I like to think of this as the contract your data must sign before it's allowed into your analysis pipeline.

library(validate)

# Let's imagine we're dealing with clinical trial data
patient_rules <- validator(
  age >= 18, 
  age <= 100,
  systolic_bp > 60, 
  systolic_bp < 250,
  gender %in% c("M", "F", "Other")
)

Notice how this looks almost like a logical expression. You're not actually filtering the data yet; you're just building a rule object. I find it helpful to group these rules by priority—put the "deal-breakers" (like a negative age) at the top.

The Confrontation

Once you have your rules, you need to actually apply them to your dataset. In the package, this is called confront(). I love that terminology because that's exactly what's happening: you're confronting your messy, real-world data with your idealized set of rules.

# Some dummy data with intentional errors
patients <- data.frame(
  patient_id = 1:4,
  age = c(25, 150, 45, -10),
  systolic_bp = c(120, 110, 40, 130),
  gender = c("M", "F", "Unknown", "F")
)

# Run the rules against the data
confrontation <- confront(patients, patient_rules)

At this point, confrontation is an object that holds the results. It hasn't changed your original patients dataframe—which is great, because you generally don't want your validation step to accidentally delete data before you've had a chance to inspect the errors.

Reading the Damage Report

The real power comes when you summarize the results. Instead of scrolling through thousands of rows, summary() gives you a high-level view of which rules are being violated and how often.

summary(confrontation)

When you run this, you'll see a table showing the percentage of rows that passed or failed each rule. If you see that 99% of your "Age" values are valid but 40% of your "Gender" values are failing, you know exactly where to focus your cleaning efforts. If you need to see the specific rows that failed, you can use get_failures() to extract just the problematic entries. It's much more surgical than trying to find the needles in the haystack using filter() manually for every single rule.




📋 Practical Task

Audit the Warehouse Inventory Log

You've been handed a CSV of warehouse stock that is notoriously messy. Your goal is to create a validation report to identify the corrupted entries before they hit the accounting system.

The Dataset:

inventory <- data.frame(
  sku = c("PROD-123", "PROD-456", "INVALID", "PROD-789", "PROD-000"),
  price = c(19.99, -5.00, 10.00, 0.00, 15.50),
  stock_level = c(100, 50, 20, -10, 10),
  category = c("Electronics", "Electronics", "Home", "Home", "Gardening")
)

Your Requirements:

  • Write a validator() object that enforces these three rules:
    1. The price must be strictly greater than 0.
    2. The stock_level must be 0 or greater.
    3. The sku must start with the string "PROD-". (Hint: use grepl("^PROD-", sku) inside your validator).
  • Use confront() to check the inventory dataframe against these rules.
  • Produce a summary() of the results to determine which rule is the most frequently violated.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.