is.na()
is.na(x) The is.na() function tests whether elements in an object are missing values (NA). It returns a logical vector of the same length as the input.
Syntax
is.na(x)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
x | any object | , | Object to test for missing values |
is.na() accepts vectors, matrices, data frames, and lists. For data frames it returns a logical matrix of the same dimensions, with TRUE at every position that holds NA. The function handles all five typed NA variants in R: NA (logical), NA_integer_, NA_real_, NA_complex_, and NA_character_. It also returns TRUE for NaN, since NaN is a special case of missing value.
Examples
Detecting NA values
x <- c(1, 2, NA, 4, NA, 6)
is.na(x)
# [1] FALSE FALSE TRUE FALSE TRUE FALSE
# Count NA values
sum(is.na(x))
# [1] 2
Wrapping is.na() in sum() is the standard idiom for counting missing values because R coerces TRUE to 1 and FALSE to 0 in arithmetic contexts. For a data frame, colSums(is.na(df)) gives per-column counts and rowSums(is.na(df)) gives per-row counts, which together help you decide whether to drop columns, impute values, or filter incomplete cases before modeling.
Working with different data types
# Character vector with NA
y <- c("apple", NA, "banana", NA)
is.na(y)
# [1] FALSE TRUE FALSE TRUE
# Data frame with NA
df <- data.frame(x = c(1, NA, 3), y = c("a", "b", NA))
is.na(df)
# x y
# [1] FALSE FALSE
# [2] TRUE FALSE
# [3] FALSE TRUE
When applied to a data frame, is.na() returns a logical matrix, not a data frame. Each cell corresponds to one position in the original data. This matrix representation is useful for visualizing missingness patterns, but for programmatic use you typically want to aggregate it with colSums() or rowSums() to get counts, or use complete.cases(df) to identify rows with no missing values at all.
Common patterns
Removing NA values
x <- c(1, 2, NA, 4, NA, 6)
x[!is.na(x)]
# [1] 1 2 4 6
# Using na.omit
na.omit(x)
# [1] 1 2 4 6
# attr(,"na.action")
# [1] 3 5
# attr(,"class")
# [1] "omit"
The difference between x[!is.na(x)] and na.omit(x) is that na.omit() attaches an attribute recording which positions were removed. This attribute is used by na.action() and by modeling functions like lm() to report how many observations were excluded. For simple data cleaning where you do not need the index tracking, the bracket approach with !is.na() is lighter and does not carry extra metadata.
Conditional handling of NA
x <- c(10, 20, NA, 40, 50)
# Replace NA with 0
ifelse(is.na(x), 0, x)
# [1] 10 20 0 40 50
# Use replace_na from tidyr
# replace_na(x, 0)
ifelse(is.na(x), replacement, x) is the base R pattern for substituting missing values with a default. The vectorized ifelse() tests each element and returns the replacement where the test is TRUE and the original value where it is FALSE. For data frames, tidyr::replace_na() handles column-specific replacements in a single call, and dplyr::coalesce() returns the first non-NA value from a set of alternatives, which is handy for filling gaps from a fallback column.
Using with data frames
df <- data.frame(
name = c("Alice", "Bob", "Charlie"),
score = c(85, NA, 92)
)
# Find rows with NA
df[is.na(df$score), ]
# name score
# 2 Bob NA
# Remove rows with NA
df[!is.na(df$score), ]
# name score
# 1 Alice 85
# 3 Charlie 92
is.na() in practice
is.na() returns TRUE for NA, NA_integer_, NA_real_, NA_complex_, NA_character_, and NaN. It returns FALSE for all other values. This means is.na(NaN) is TRUE, NaN is a special case of NA. Use is.nan() if you specifically need to distinguish computational NaN from missing NA.
sum(is.na(x)) counts missing values, a standard first step when auditing new data. mean(is.na(x)) gives the proportion missing. For data frames, colSums(is.na(df)) counts missing values per column, which is the most common way to survey missingness across a dataset.
which(is.na(x)) returns the positions of missing values, useful for understanding where gaps occur in time series or sequences. x[!is.na(x)] removes missing values, equivalent to na.omit(x) for atomic vectors. For data frames, na.omit(df) removes rows with any NA, while df[complete.cases(df), ] does the same with explicit row selection.
Replacing NA with a default value: x[is.na(x)] <- 0 replaces in-place, replace(x, is.na(x), 0) returns a copy, and tidyr::replace_na(x, 0) is the tidyverse equivalent. dplyr::coalesce(x, 0) returns the first non-NA value from a list of alternatives.
is.na() returns a logical vector with TRUE at every position that is NA. It handles NA, NA_integer_, NA_real_, NA_complex_, and NA_character_, all typed missing values. NaN is also considered NA by is.na() but not by is.nan(). For data frames, is.na(df) returns a logical matrix of the same dimensions. Use sum(is.na(x)) to count missing values and mean(is.na(x)) to get the missing rate.
is.na() returns a logical vector with TRUE at positions that hold NA. R has five typed NA variants, NA (logical), NA_integer_, NA_real_, NA_complex_, and NA_character_ — and is.na() returns TRUE for all of them. NaN is also considered NA by is.na(), though is.nan() returns FALSE for plain NA.
For data frames, is.na(df) returns a logical matrix of the same dimensions. colSums(is.na(df)) counts missing values per column, and rowSums(is.na(df)) counts per row.
sum(is.na(x)) is the idiomatic way to count missing values in a vector. mean(is.na(x)) gives the missing proportion. any(is.na(x)) is a fast early-exit check.
Assigning NA to a subset clears those values: x[x < 0] <- NA is the base R way to replace values meeting a condition with missing. In tidyverse code, na_if(x, condition) or replace_na(x, value) are more readable alternatives.