Removing and Replacing NA Values
Apply na.omit(), complete.cases(), and manual replacement strategies.
Removing and Replacing NA Values is a free R Academy lesson on CoddyKit. This is lesson 3 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the R Academy learning path, and your progress syncs across the web and the CoddyKit app. The R Academy course includes 4 lessons in total.
Strategies for Handling NA
There are three main strategies for handling missing values: remove them, replace them with a constant, or impute them using a statistical estimate. The right approach depends on your data and analysis goals.
data_vals <- c(88, NA, 72, NA, 91, 65, NA, 78)
cat('Original data:', data_vals, '
')
cat('NA count:', sum(is.na(data_vals)), '
')
# Strategy 1: remove
cat('After removal:', data_vals[!is.na(data_vals)], '
')
# Strategy 2: replace with 0
replaced <- data_vals; replaced[is.na(replaced)] <- 0
cat('Replaced with 0:', replaced, '
')Removing NAs with x[!is.na(x)]
The most direct way to remove NAs from a vector is logical subsetting: x[!is.na(x)]. This keeps only the elements where is.na(x) is FALSE (i.e., present values).
response_times <- c(1.2, NA, 0.9, 1.5, NA, 1.1, 0.8, NA, 1.3)
cat('With NAs: ', response_times, '
')
cat('Length:', length(response_times), '
')
clean_times <- response_times[!is.na(response_times)]
cat('Without NAs: ', clean_times, '
')
cat('Length:', length(clean_times), '
')
cat('Mean after removal:', round(mean(clean_times), 3), '
')na.omit() for Vectors
na.omit(x) removes NA values from a vector. It is equivalent to x[!is.na(x)] but also stores the positions of the removed NAs in an attribute called 'na.action'.
scores <- c(88, NA, 72, NA, 91, 65, NA, 78)
clean_scores <- na.omit(scores)
cat('Original:', scores, '
')
cat('Cleaned: ', as.numeric(clean_scores), '
')
# na.omit records which positions were removed
removed_at <- attr(clean_scores, 'na.action')
cat('NAs were at positions:', removed_at, '
')na.omit() for Data Frames
When applied to a data frame, na.omit(df) removes any row that contains at least one NA. This is called listwise deletion — the entire observation is dropped.
df <- data.frame(
name = c('Alice', 'Bob', 'Carol', 'Dave', 'Eve'),
age = c(28, NA, 32, 45, 29),
salary = c(55000, 72000, NA, 90000, 61000)
)
cat('Original rows:', nrow(df), '
')
df_clean <- na.omit(df)
cat('After na.omit rows:', nrow(df_clean), '
')
print(df_clean)complete.cases() — Row-Wise Completeness
complete.cases(df) returns a logical vector with TRUE for rows that have no missing values. Use it to filter complete rows or to identify which rows are incomplete.
df <- data.frame(
id = 1:5,
x = c(1, NA, 3, 4, NA),
y = c(NA, 2, 3, NA, 5)
)
cc <- complete.cases(df)
cat('Complete cases (T/F):', cc, '
')
cat('Complete rows:
')
print(df[cc, ])
cat('Number complete:', sum(cc), '
')Replacing NA with a Constant
To replace NA with a specific value, use logical assignment: x[is.na(x)] <- value. Common replacements include 0 for counts, the mean/median for continuous data, or a category label for factors.
# Replace with 0
counts <- c(5, NA, 3, NA, 8, 1, NA, 4)
counts_filled <- counts
counts_filled[is.na(counts_filled)] <- 0
cat('Original:', counts, '
')
cat('Filled: ', counts_filled, '
')
# Replace with mean of present values
mean_val <- mean(counts, na.rm = TRUE)
counts_mean <- counts
counts_mean[is.na(counts_mean)] <- mean_val
cat('Mean-filled:', round(counts_mean, 1), '
')replace() — Functional Replacement
replace(x, list, values) returns a modified copy of x where elements at positions list are replaced with values. It is the functional (non-modifying) approach to replacement.
temps <- c(22.1, NA, 19.8, NA, 25.1)
cat('Original:', temps, '
')
# Replace NAs with the median
median_temp <- median(temps, na.rm = TRUE)
filled_temps <- replace(temps, is.na(temps), median_temp)
cat('Filled: ', filled_temps, '
')
cat('Original unchanged:', temps, '
') # original not modifiedForward-Fill (Last Observation Carried Forward)
A common imputation strategy is forward-fill (LOCF): replace each NA with the last known value. This is used for time series data where measurements carry forward until updated.
# Manual forward-fill
readings <- c(10, NA, NA, 13, NA, 15, NA, NA, 18)
filled <- readings
for (i in seq_along(filled)) {
if (is.na(filled[i]) && i > 1) {
filled[i] <- filled[i - 1]
}
}
cat('Original: ', readings, '
')
cat('Forward-filled:', filled, '
')Replacing NA in Character Vectors
The same techniques work for character vectors. Replacing NA in strings with a label like 'Unknown' or 'Missing' is common in categorical data analysis.
categories <- c('A', NA, 'B', 'A', NA, 'C', NA, 'B')
cat('Original:', categories, '
')
# Replace with 'Unknown'
filled_cat <- replace(categories, is.na(categories), 'Unknown')
cat('Filled: ', filled_cat, '
')
# Count each category
cat('Table:
')
print(table(filled_cat))Conditional Replacement Strategy
Sometimes you want different replacement values based on another column's value. Use indexing with conditions to apply targeted replacements.
# Scores: replace NA with group mean
group <- c('A', 'A', 'B', 'B', 'A', 'B')
scores <- c(85, NA, 72, NA, 90, 78)
mean_a <- mean(scores[group == 'A'], na.rm = TRUE)
mean_b <- mean(scores[group == 'B'], na.rm = TRUE)
imputed <- scores
imputed[is.na(imputed) & group == 'A'] <- mean_a
imputed[is.na(imputed) & group == 'B'] <- mean_b
cat('Original:', scores, '
')
cat('Imputed: ', imputed, '
')NA Removal Methods Summary
Summary of NA handling tools in R:
x[!is.na(x)]— remove NAs from vectorna.omit(x)— remove NAs (also records positions)na.omit(df)— remove incomplete rows from data framecomplete.cases(df)— logical vector: TRUE for complete rowsx[is.na(x)] <- val— replace NAs in placereplace(x, is.na(x), val)— functional replacement (returns copy)
v <- c(5, NA, 8, NA, 3, 7)
cat('Remove: ', v[!is.na(v)], '
')
cat('Replace with 0: ', replace(v, is.na(v), 0), '
')
cat('Replace with mean:', replace(v, is.na(v), mean(v, na.rm=TRUE)), '
')Quick Check
What does na.omit(c(1, NA, 3, NA, 5)) return?
Recap: Removing and Replacing NAs
Great work! Key takeaways from this lesson:
x[!is.na(x)]andna.omit(x)remove NAs from a vectorna.omit(df)performs listwise deletion (removes any row with an NA)complete.cases(df)identifies rows with no missing valuesx[is.na(x)] <- valuereplaces NAs in placereplace(x, is.na(x), value)returns a modified copy without changing the original- Choose your strategy based on the reason data is missing and how much is missing
# Complete workflow: audit, then handle
data_raw <- c(82, NA, 75, NA, 91, 68, NA, 79)
cat('Missing:', sum(is.na(data_raw)), '/', length(data_raw), '
')
# Replace with median (robust to outliers)
imputed <- replace(data_raw, is.na(data_raw), median(data_raw, na.rm=TRUE))
cat('Before imputation mean:', round(mean(data_raw, na.rm=TRUE), 2), '
')
cat('After imputation mean: ', round(mean(imputed), 2), '
')Learn R with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 43
- Lessons
- 159
Frequently Asked Questions
Is the “Removing and Replacing NA Values” lesson free?
Yes — any 3 lessons of the R Academy learning path, including “Removing and Replacing NA Values”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The R Academy course includes 4 lessons in total.
What will I learn in “Removing and Replacing NA Values”?
Apply na.omit(), complete.cases(), and manual replacement strategies. You practise R Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start R Academy?
No prior experience is required. R Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.
How long does the “Removing and Replacing NA Values” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this R Academy lesson?
Yes. Every R Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Understanding NA in R
- Detecting and Counting Missing Values
- Removing and Replacing NA Values
- NA in Calculations and Aggregations