Introduction
Welcome to the next lesson in our journey. In our previous explorations of data frames, you've likely noticed the NA symbol popping up in summaries and data views. As we discussed, these represent missing values, an inevitable reality in nearly all real-world data, from clinical trials to population surveys. Ignoring or mishandling them can lead to incorrect calculations and flawed conclusions.
This lesson tackles this fundamental challenge head-on. Building on our last session on factors, we will now learn how to formally handle missing values. Our focus will be on two core skills: detecting NAs using the is.na() function, and managing them in calculations using function arguments like na.rm = TRUE. Mastering this is a non-negotiable step in preparing clean, reliable data for the statistical analysis and visualization you aim to perform.
1. The "Viral" Nature of NA
In R, NA (Not Available) is not just a placeholder; it's a special logical value with specific properties. One of its most important characteristics is its "viral" nature: any arithmetic or logical operation that includes an NA will almost always result in NA.
For example, what is 5 + NA? We don't know what the missing value is, so the result is also unknown. R's answer is NA. This is a deliberate and crucial feature of the language. It acts as a safety mechanism, preventing you from accidentally getting a numerical result from an incomplete calculation. If R simply ignored NAs by default, you could easily compute a misleading average or sum without ever realizing your data was incomplete.
Let's see how this plays out with a common statistical function.
19. Dealing with missing values in R - Blair's Science Desk
This article from Blair's Science Desk provides a perfect illustration of the problem. It shows what happens when you try to calculate the mean of a vector containing NAs.
Please read the first two sections, "The NA" and the following section. In these sections, read about handling missing values. Pay attention to how R returns NA by default and the introduction of the na.rm argument as the solution.
As the article demonstrates, R forces you to be explicit about your intentions. This is a core principle of good data analysis: you, the analyst, must decide how missing data should be handled.
2. Finding and Counting Missing Values with is.na()
Before you can handle missing values, you must first find them. R's primary tool for this is the is.na() function. It takes a vector, data frame, or other R object and returns an object of the same size, but with TRUE wherever an NA was present and FALSE otherwise.
This TRUE/FALSE output is incredibly useful because R treats TRUE as 1 and FALSE as 0 in mathematical operations. This allows for a simple and powerful way to count missing values.
sum(is.na(x))will count the total number ofNAs in a vectorx.colSums(is.na(df))is a very common idiom that will give you the count ofNAs in each column of a data framedf.
This guide from the UC Business Analytics R Programming Guide provides clear code examples for identifying and counting NAs.
Please read the section on testing missing values. Focus on how is.na() is applied to both a vector and a data frame. Then, study the examples that use sum() and colSums() to count the NAs.
To see this in action, the following short video provides a good visual summary of applying is.na() and then sum(is.na()) to a dataset.
Handling NA in R | is.na, na.omit & na.rm Functions for Missing Values
This video from the Statistics Globe channel demonstrates the is.na() and sum(is.na()) functions.
About a minute in, watch the segment from identifying NAs with is.na(), and then the following part on counting them with sum().
3. Calculating with Missing Data: The na.rm Argument
As we saw earlier, functions like mean(), median(), sum(), sd(), and min() will return NA if their input contains any missing values. The solution is the na.rm = TRUE argument, where rm stands for "remove". By adding this argument, you are telling the function to strip out the NA values before performing the calculation.
This is the most common and direct way to handle missing values for a specific calculation without modifying your underlying data.
Handling NA in R | is.na, na.omit & na.rm Functions for Missing Values
The same Statistics Globe video provides a very clear "before and after" demonstration of using na.rm.
Please watch the segment about four minutes in on removing missing values during analysis. Notice how the mean() function fails at first and then works perfectly once na.rm = TRUE is added.
This approach is powerful because it's localized. You deal with the NAs for one specific summary statistic, but the NAs remain in your original data frame, which is important. You may want to handle them differently for other analyses (for instance, by removing the entire row, which we'll touch on next).
4. A Note on Excluding Rows
Sometimes, ignoring an NA for a single calculation isn't enough. For some analyses, you might decide that any observation (row) with a missing value in a critical variable is unusable. In these cases, you might want to remove the entire row.
Base R offers two common functions for this: na.omit() and complete.cases(). Both can be used to filter a data frame, keeping only the rows that have no missing values. However, this method should be used with extreme caution.
19. Dealing with missing values in R - Blair's Science Desk
This article from Blair's Science Desk clearly demonstrates na.omit and provides a critical warning about its use.
Please read the sections on na.omit and, most importantly, the warning about using it on sparse data. The example of how na.omit can accidentally delete your entire dataset is a memorable and important lesson.
The danger highlighted in the reading is significant, especially in clinical research where a participant might have complete data on primary outcomes but be missing a secondary demographic variable. Using na.omit() carelessly could discard valuable data.
The tidyverse offers a more controlled function for this, tidyr::drop_na(), which we will cover in a future lesson. For now, the key takeaway is to prefer the na.rm argument for calculations and to be very deliberate if you choose to remove entire rows of data.
Let's Practice
Let's apply these concepts in your clinical-trial-practice RStudio Project. You can create a new script, perhaps named 05-missing-values.R.
-
Load packages and data. We will use the
penguinsdataset again, as it contains several missing values.library(tidyverse) penguins_url <- "https://raw.githubusercontent.com/allisonhorst/palmerpenguins/main/inst/extdata/penguins.csv" penguins_data <- read_csv(penguins_url) -
Task 1: Inspect and Count
NAs.- First, get a quick overview with
summary(). This function, as we've seen, conveniently lists the number ofNAs per column.summary(penguins_data) - Now, let's practice using our new tools to get the same information. Get a count of
NAs for each column usingcolSums()andis.na().
Your results should match thecolSums(is.na(penguins_data))summary()output. This is a great way to start any data exploration.
- First, get a quick overview with
-
Task 2: Practice with
na.rm.- Try to calculate the average body mass of the penguins. What happens?
R returnsmean(penguins_data$body_mass_g)NAbecause thebody_mass_gcolumn contains missing values. - Now, perform the calculation correctly using
na.rm = TRUE.
You should now get a valid numerical answer.mean(penguins_data$body_mass_g, na.rm = TRUE)
- Try to calculate the average body mass of the penguins. What happens?
-
Task 3: Filter to Inspect
NARows.- Sometimes it's useful to look at the specific rows that contain missing data. You can combine the
filter()function (which you'll learn more about soon) withis.na()to do this. Let's find all the penguins where thesexinformation is missing.penguins_data %>% filter(is.na(sex)) - This shows you all 11 rows where
sexisNA. Inspecting these rows might give you clues about why the data is missing. For example, are they all from a particular island or year? This is a key step in thoughtful data analysis.
- Sometimes it's useful to look at the specific rows that contain missing data. You can combine the
Conclusion
You have now learned the essential techniques for one of the most common tasks in data cleaning: handling missing values. This foundational skill prevents errors and forces a more deliberate and conscious approach to data analysis.
Key Takeaways:
NAis Viral: R's default behavior is to propagateNAs in calculations to prevent you from getting a silently incorrect answer.- Detect with
is.na(): Theis.na()function is your primary tool for locating missing values. Combining it withsum()orcolSums()allows you to quickly quantify the extent of missing data in your dataset. - Calculate with
na.rm = TRUE: For summary statistics (mean,sd,median, etc.), use thena.rm = TRUEargument to perform the calculation on the available data without altering your original dataset. - Exclude Rows with Caution: Functions like
na.omit()remove entire rows containingNAs. While sometimes necessary, this can lead to significant data loss and should be used with careful consideration.
Preview of the Next Lesson:
So far in this module, we've learned how to bring data into R from various file types and how to perform initial inspections, including dealing with factors and missing values. The final step in this part of the data workflow is saving your work. In our next lesson, we will learn how to export data frames to CSV files using readr::write_csv(), completing the import-clean-export cycle.