mutate() 根据已有列创建新列,也可以覆盖现有列。表达式按书写顺序求值,因此后面的新列可以引用同一次调用中前面刚创建的列。
library(dplyr)
students <- tibble(
name = c("Alice", "Bob", "Charlie"),
score = c(90, 85, 88),
age = c(20, 21, 19)
)
新增与修改列
students |>
mutate(double_score = score * 2)
同时创建多个变量:
students |>
mutate(
score_fraction = score / 100,
score_percent = score_fraction * 100
)
覆盖现有列:
students |>
mutate(score = round(score / 10, 1))
覆盖会丢失原值。若后续需要核查,先创建一个有明确单位的新列通常更安全。
控制新列位置
students |>
mutate(double_score = score * 2, .before = score)
students |>
mutate(double_score = score * 2, .after = name)
复杂管道中,也可以先完成计算,再用 relocate() 统一排列。
控制保留哪些原列
.keep 决定输出保留的输入列:
| 值 | 保留内容 |
|---|---|
"all" |
所有输入列,默认 |
"used" |
新表达式使用过的输入列 |
"unused" |
未被表达式使用的输入列 |
"none" |
只保留分组列和新列 |
students |>
mutate(double_score = score * 2, .keep = "used")
students |>
mutate(double_score = score * 2, .keep = "none")
.keep 适合制作中间结果或最终特征表,但不应为了输出简短而过早丢掉标识列和核查字段。
条件转换
二选一使用 if_else():
students |>
mutate(result = if_else(score >= 90, "high", "other"))
多个条件使用 case_when():
students |>
mutate(
grade = case_when(
score >= 90 ~ "A",
score >= 80 ~ "B",
TRUE ~ "C"
)
)
条件从上到下匹配,先满足的分支生效。范围重叠时,顺序就是业务规则的一部分。
使用 across() 批量处理列
measurements <- tibble(
id = 1:3,
height = c(170.2, 168.8, 181.1),
weight = c(65.4, 58.9, 82.2)
)
measurements |>
mutate(
across(
c(height, weight),
round,
digits = 0
)
)
生成新列而不覆盖原列:
measurements |>
mutate(
across(
c(height, weight),
~ round(.x, 0),
.names = "{.col}_rounded"
)
)
也可以按类型选择:
measurements |>
mutate(across(where(is.numeric), as.double))
批量转换前要确认所选列共享相同的含义和单位,不能因为它们都是 numeric 就自动采用相同处理。
分组内转换
scores <- tibble(
group = c("A", "A", "B", "B"),
score = c(10, 12, 20, 24)
)
scores |>
mutate(
group_mean = mean(score),
centered = score - group_mean,
.by = group
)
.by 只作用于这一次 mutate(),结果不会保留分组状态。
缺失值传播
多数数值运算会保留 NA:
tibble(x = c(1, NA, 3)) |>
mutate(y = x * 2)
汇总函数是否移除缺失,需要明确指定:
scores |>
mutate(group_mean = mean(score, na.rm = TRUE), .by = group)
na.rm = TRUE 只是忽略缺失,并不说明缺失机制合理。数据清洗和统计分析中仍需记录缺失数量与处理依据。
保持单位和类型清晰
patients |>
mutate(
height_m = height_cm / 100,
bmi = weight_kg / height_m^2
)
新列名称应表达单位和含义。mutate() 能让计算很短,但可复现性来自明确的变量定义,而不是管道长度。