Skip to Content
Course content

13: Working with NA and Missing Data

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

Imagine you're reviewing a stack of handwritten job applications. Most candidates filled out every field, but a few left the "Years of Experience" box completely blank. Now, if you were to calculate the average experience of all applicants, you couldn't just treat those blank boxes as zeros. If someone left it blank, it doesn't mean they have zero experience; it means the information is missing. If you treat a blank as a zero, you're lying to your data and dragging your average down unfairly.

In R, that blank box is NA (Not Available). It's a special logical constant that tells R, "I don't know what goes here." Here is how that maps to the code you'll be writing:

  • The Blank Box: This is the NA value. It can exist in numeric, character, or logical vectors.
  • Checking for Blanks: You can't just ask R "Is this equal to NA?" (I'll explain why in a second). Instead, you use a specific tool: is.na().
  • Dealing with the Gaps: When you run a calculation, you have to decide whether to throw away the "incomplete applications" (na.rm = TRUE) or let the missing data signal that the result is also unknown.

The Trap of the Equality Operator

Here is the first thing that trips up almost everyone I've mentored. You'll be tempted to find missing values using my_vector == NA. Don't do it. It won't work.

In R, NA is contagious. If you ask "Is this value equal to something unknown?", the answer is... unknown. So R returns NA for every single element instead of a TRUE or FALSE. To actually find the holes in your data, you have to use is.na().

# This is the wrong way
ages <- c(25, 30, NA, 42)
ages == NA 
# Result: NA NA NA NA (Useless!)

# This is the right way
is.na(ages)
# Result: FALSE FALSE TRUE FALSE

Stopping the Contagion in Calculations

I've seen plenty of developers pull their hair out because sum() or mean() suddenly started returning NA. This happens because R is being cautious. If one value in your set is unknown, R assumes the total sum must also be unknown.

If you've decided that it's acceptable to just ignore the missing entries and calculate the average of whatever is actually there, you use the na.rm (NA remove) argument. I personally find it's better to be explicit here so the next person reading your code knows you didn't just forget about the missing data.

# Let's say we have daily temperature readings, but the sensor died on Tuesday
temps <- c(72, 75, NA, 68, 71)

mean(temps) 
# Result: NA (R is playing it safe)

mean(temps, na.rm = TRUE) 
# Result: 71.5 (R ignores the NA and averages the rest)

Cleaning the Whole Table

Sometimes, you don't want to handle NAs column by column. If a row in your data frame is missing critical information, that whole record might be useless to you. In those cases, you can use na.omit(). This effectively tosses any row that contains at least one NA.

Just a word of caution: be careful with this. If your dataset is "messy" and every row has at least one random missing value in some unimportant column, na.omit() will wipe out your entire dataset before you can blink. Always check how many NAs you have before you start deleting rows.

# A small dataset of users
users <- data.frame(
  name = c("Alice", "Bob", "Charlie"),
  email = c("alice@email.com", NA, "charlie@email.com"),
  age = c(25, 30, NA)
)

# This removes Bob (missing email) and Charlie (missing age)
clean_users <- na.omit(users)
# Result: Only Alice remains



📋 Practical Task

Fixing the Broken Sensor Log

You have been handed a numeric vector representing the voltage readings from a power grid sensor over 10 minutes. However, the sensor flickered, and some readings were lost (recorded as NA). Your goal is to clean this data and find the average voltage.

Your Task:

  1. Create a vector called voltage_readings with the following values: 12.1, 12.0, NA, 12.2, NA, 11.9, 12.1, NA, 12.0, 12.1.
  2. Write a line of code that returns a logical vector identifying exactly which readings are missing.
  3. Calculate the mean voltage of the readings. Ensure your result is a number, not NA.
  4. Create a new vector called filtered_readings that contains only the non-missing values (Hint: use the ! operator with is.na() inside square brackets []).
Rating
0 0

There are no comments for now.

to be the first to leave a comment.