0Pricing
R Academy · Lesson

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 — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the R Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

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 modified

Forward-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 vector
  • na.omit(x) — remove NAs (also records positions)
  • na.omit(df) — remove incomplete rows from data frame
  • complete.cases(df) — logical vector: TRUE for complete rows
  • x[is.na(x)] <- val — replace NAs in place
  • replace(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)] and na.omit(x) remove NAs from a vector
  • na.omit(df) performs listwise deletion (removes any row with an NA)
  • complete.cases(df) identifies rows with no missing values
  • x[is.na(x)] <- value replaces NAs in place
  • replace(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), '
')

Frequently asked questions

Is the “Removing and Replacing NA Values” lesson free?

Yes — the full text of “Removing and Replacing NA Values” is free to read here on the web, and the R Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the R Academy course, upgrade to CoddyKit PRO.

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; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

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

  1. Understanding NA in R
  2. Detecting and Counting Missing Values
  3. Removing and Replacing NA Values
  4. NA in Calculations and Aggregations
← Back to R Academy