数据整理经常围绕两个方向展开:对列决定保留哪些变量和如何排列,对行决定保留哪些观测。dplyr 为这些任务提供了职责明确的函数。
library(dplyr)
df <- tibble(
id = 1:8,
group = c("A", "B", "A", "B", "C", "C", "A", "B"),
score = c(95, 81, 88, 60, 72, NA, 87, 100),
score_2 = c(92, 79, 90, 65, 75, 70, 85, 98),
label = c("pos", "neg", "pos", "neg", "pos", "neg", "neg", "pos")
)
select():选择或排除列
df |>
select(id, group, score)
列名可以按范围和规则选择:
df |> select(id:score)
df |> select(starts_with("score"))
df |> select(ends_with("_2"))
df |> select(contains("core"))
df |> select(matches("^s"))
df |> select(where(is.numeric))
排除列:
df |> select(-label)
df |> select(-starts_with("score"))
常用 tidyselect 辅助函数包括:
| 辅助函数 | 选择规则 |
|---|---|
starts_with() |
指定前缀 |
ends_with() |
指定后缀 |
contains() |
包含固定文本 |
matches() |
匹配正则表达式 |
num_range() |
带连续编号的列名 |
where() |
列本身满足类型判断 |
all_of() |
严格使用字符向量中的列名 |
any_of() |
忽略字符向量中不存在的列名 |
编程时,列名存放在字符向量中应使用 all_of() 或 any_of():
needed <- c("id", "group", "score")
df |> select(all_of(needed))
relocate():只调整列顺序
relocate() 不增删列,只移动位置:
df |> relocate(score)
df |> relocate(score, .after = id)
df |> relocate(starts_with("score"), .before = group)
df |> relocate(where(is.character), .after = last_col())
需要选择并重新排列一部分列时使用 select();需要保留全部列、只调整位置时使用 relocate()。
filter():按条件筛选行
df |> filter(group == "A")
df |> filter(group == "A", score >= 90)
df |> filter(group == "A" & score >= 90)
df |> filter(group == "A" | score >= 90)
逗号连接的多个条件等价于逻辑与。类别集合使用 %in%:
target_ids <- c(1, 3, 5)
df |> filter(id %in% target_ids)
区间可以使用两个比较,或 between():
df |> filter(score >= 80, score <= 95)
df |> filter(between(score, 80, 95))
筛选缺失值
df |> filter(is.na(score))
df |> filter(!is.na(score))
涉及 NA 的比较会得到 NA 而非 TRUE,filter() 只保留条件明确为 TRUE 的行。因此 score != NA 不能用于排除缺失。
slice_*():按位置或顺序抽取行
filter() 根据行的值判断;slice_*() 根据位置、极值或抽样规则选择行。
df |> slice(1:3)
df |> slice_head(n = 3)
df |> slice_tail(n = 2)
df |> slice_min(order_by = score, n = 2)
df |> slice_max(order_by = score, n = 2)
df |> slice_sample(prop = 0.25)
极值存在并列时,默认可能返回超过 n 行。只需要固定数量时显式设置:
df |>
slice_max(order_by = score, n = 1, with_ties = FALSE)
抽样结果需要复现时先设置随机种子:
set.seed(42)
df |> slice_sample(n = 3)
组内抽取
df |>
group_by(group) |>
slice_max(order_by = score, n = 1, with_ties = FALSE) |>
ungroup()
也可以使用局部分组:
df |>
slice_max(
order_by = score,
n = 1,
with_ties = FALSE,
by = group
)
组内“最高一行”必须先决定并列如何处理,以及缺失是否参与。
distinct():识别唯一组合
完全相同的行去重:
df |> distinct()
查看变量的唯一组合:
df |> distinct(group, label)
按键去重并保留整行:
df |> distinct(id, .keep_all = TRUE)
distinct() 默认保留第一次出现的记录。若业务规则是保留最新或最高记录,应先明确排序:
records <- tibble(
id = c(1, 1, 2, 2),
date = as.Date(c("2025-01-01", "2025-02-01", "2025-01-10", "2025-01-20")),
value = c(8, 10, 6, 9)
)
records |>
arrange(id, desc(date)) |>
distinct(id, .keep_all = TRUE)
去重规则应能用字段表达。只写“删除重复值”而不说明判定键和保留规则,会让数据清理不可复现。
一条完整流水线
result <- df |>
filter(!is.na(score), group %in% c("A", "B")) |>
select(id, group, starts_with("score"), label) |>
slice_max(
order_by = score,
n = 1,
with_ties = FALSE,
by = group
) |>
relocate(group, id)
把列选择、行条件、抽取规则和最终排列分开写,管道会比一个复杂下标表达式更容易核查。