0Pricing
R Academy · 课时

移除与替换 NA 值

应用 na.omit()、complete.cases() 和手动替换策略

移除与替换 NA 值 是 CoddyKit 上的免费 R Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 R Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 R Academy 课程共包含 4 节课。

处理 NA 的策略

处理缺失值主要有三种策略:移除缺失值、用常量替换缺失值,或使用统计估计值进行插补。正确的方法取决于您的数据和分析目标。

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, '
')

使用 x[!is.na(x)] 移除 NA

从向量中移除 NA 最直接的方法是逻辑子集:x[!is.na(x)]。它只保留 is.na(x) 为 FALSE 的元素(即存在的值)。

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()

na.omit(x) 会从向量中移除 NA。它等价于 x[!is.na(x)],但还会将被移除 NA 的位置存储在名为 '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()

应用于数据框时,na.omit(df) 会移除包含至少一个 NA 的所有行。这称为按行删除——整个观测都会被移除。

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() — 按行检查完整性

complete.cases(df) 会返回一个逻辑向量,没有缺失值的行对应 TRUE。您可以使用它筛选完整行,或找出不完整的行。

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), '
')

用常量替换 NA

要将 NA 替换为特定值,请使用逻辑赋值:x[is.na(x)] <- value。常见的替换值包括:计数数据使用 0,连续数据使用均值或中位数,因子使用类别标签。

# 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() — 函数式替换

replace(x, list, values) 会返回 x 的修改副本,将位置为 list 的元素替换为 values。这是函数式(不直接修改原对象)的替换方法。

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

向前填充(LOCF)

一种常见的插补策略是向前填充(LOCF):用最后一个已知值替换每个 NA。这适用于时间序列数据,因为测量值会一直沿用到下一次更新。

# 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, '
')

替换字符向量中的 NA

相同的技术也适用于字符向量。在分类数据分析中,常见做法是将字符串中的 NA 替换为 'Unknown' 或 'Missing' 这样的标签。

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))

条件替换策略

有时,您需要根据另一列的值使用不同的替换值。请使用带条件的索引来执行有针对性的替换。

# 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 移除方法总结

R 中 NA 处理工具总结:

  • x[!is.na(x)] — 从向量中移除 NA
  • na.omit(x) — 移除 NA(同时记录位置)
  • na.omit(df) — 从数据框中移除不完整的行
  • complete.cases(df) — 逻辑向量:完整行对应 TRUE
  • x[is.na(x)] <- val — 原位替换 NA
  • replace(x, is.na(x), val) — 函数式替换(返回副本)
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)), '
')

快速检查

na.omit(c(1, NA, 3, NA, 5)) 会返回什么?

回顾:移除和替换 NA

做得很棒!本课的要点如下:

  • x[!is.na(x)] 和 na.omit(x) 会从向量中移除 NA
  • na.omit(df) 执行按行删除(移除包含 NA 的所有行)
  • complete.cases(df) 可找出不含缺失值的行
  • x[is.na(x)] <- value 会原位替换 NA
  • replace(x, is.na(x), value) 返回修改后的副本,不会改变原对象
  • 请根据数据缺失的原因和缺失量选择策略
# 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), '
')

常见问题解答

「移除与替换 NA 值」课时是免费的吗?

是的 — 「移除与替换 NA 值」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 R Academy 课程的其余内容,请升级到 CoddyKit PRO。 R Academy 课程共包含 4 节课。

「移除与替换 NA 值」这节课中我会学到什么?

应用 na.omit()、complete.cases() 和手动替换策略 你通过在浏览器中直接运行的动手代码来练习 R Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 R Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 R Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「移除与替换 NA 值」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 R Academy 课中编写并运行代码吗?

能。每节 R Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 理解 R 中的 NA
  2. 检测并统计缺失值
  3. 移除与替换 NA 值
  4. 计算与聚合中的 NA
← 返回 R Academy