library(tidyverse)5 R 数据处理进阶
6 R 数据处理进阶
上一章我们学习了 R 的基础操作。本章将介绍 tidyverse——R 中最流行的数据处理生态系统,它能让你的数据处理代码更简洁、更易读。
6.1 tidyverse 简介
tidyverse 是一组协同工作的 R 包集合,由 Hadley Wickham 等人开发:
加载 tidyverse 会同时加载以下核心包:
| 包名 | 功能 |
|---|---|
| dplyr | 数据操作(筛选、排序、汇总) |
| tidyr | 数据重塑(长宽格式转换) |
| ggplot2 | 数据可视化 |
| readr | 数据读取 |
| stringr | 字符串处理 |
| forcats | 因子处理 |
| tibble | 增强版数据框 |
| purrr | 函数式编程 |
6.2 管道操作符
管道操作符 |> 是 tidyverse 编程风格的核心。它的作用很简单:把左边的结果,作为右边函数的第一个参数传入。
# 传统写法(从内向外读,难以理解)
round(mean(c(1.5, 2.3, 3.7, 4.1)), 1)
# 管道写法(从左到右读,清晰直观)
c(1.5, 2.3, 3.7, 4.1) |>
mean() |>
round(1)上面的管道写法等价于:
c(1.5, 2.3, 3.7, 4.1)的结果传给mean()→ 得到2.92.9传给round(1)→ 即round(2.9, 1)→ 得到2.9
你可以把 |> 读作”然后”:取这些数字,然后求平均,然后四舍五入。
Tip管道的快捷键
在 RStudio 中,按 Ctrl + Shift + M 可以快速输入管道操作符。
Note
|> 与 %>% 的区别
你可能在网上看到另一种管道 %>%(来自 magrittr 包)。两者功能基本相同,区别在于:
|>是 R 4.1+ 内置的原生管道,不需要加载任何包%>%是 magrittr 包提供的管道,需要加载 tidyverse 或 magrittr
本课程统一使用 |>。如果你在旧教程中看到 %>%,直接替换为 |> 即可。
6.2.1 示例数据
本章使用一个模拟的植物样方调查数据集:
# 创建示例数据
set.seed(2027)
survey <- tibble(
plot_id = rep(paste0("P", 1:10), each = 5),
species = sample(c("马尾松", "杉木", "桉树", "樟树", "楠木"), 50, replace = TRUE),
height = round(rnorm(50, mean = 12, sd = 4), 1),
dbh = round(rnorm(50, mean = 20, sd = 8), 1),
habitat = rep(sample(c("山脊", "山坡", "山谷"), 10, replace = TRUE), each = 5),
soil_ph = round(rnorm(50, mean = 5.5, sd = 0.8), 2)
)
# 人为加入一些缺失值
survey$height[c(3, 17, 28)] <- NA
survey$dbh[c(8, 42)] <- NA
head(survey, 10)6.3 dplyr:数据操作五大动词
6.3.1 filter() — 筛选行
# 筛选马尾松
survey |>
filter(species == "马尾松")
# 多条件筛选:株高 > 15 且 土壤 pH < 6
survey |>
filter(height > 15, soil_ph < 6)
# 或条件:马尾松或杉木
survey |>
filter(species %in% c("马尾松", "杉木"))6.3.2 select() — 选择列
# 选择特定列
survey |>
select(plot_id, species, height)
# 排除某列
survey |>
select(-soil_ph)
# 选择数值列
survey |>
select(where(is.numeric))6.3.3 mutate() — 新增/修改列
# 新增列:计算树木断面积(basal area)
survey |>
mutate(
basal_area = pi * (dbh / 200)^2, # 单位:m²
height_class = case_when(
height < 8 ~ "矮",
height < 15 ~ "中",
TRUE ~ "高"
)
) |>
head()6.3.4 arrange() — 排序
# 按株高降序排列
survey |>
arrange(desc(height)) |>
head()
# 先按样方排序,再按株高排序
survey |>
arrange(plot_id, desc(height)) |>
head()6.3.5 summarise() + group_by() — 分组汇总
# 按物种分组统计
survey |>
group_by(species) |>
summarise(
n = n(),
mean_height = mean(height, na.rm = TRUE),
sd_height = sd(height, na.rm = TRUE),
mean_dbh = mean(dbh, na.rm = TRUE)
) |>
arrange(desc(mean_height))# 按样方和生境分组
survey |>
group_by(habitat) |>
summarise(
n_trees = n(),
n_species = n_distinct(species),
mean_ph = mean(soil_ph, na.rm = TRUE)
)6.4 组合使用:数据处理流水线
dplyr 的强大之处在于可以用管道将多个操作串联起来:
# 完整的数据处理流水线
result <- survey |>
filter(!is.na(height), !is.na(dbh)) |> # 1. 去除缺失值
mutate(basal_area = pi * (dbh / 200)^2) |> # 2. 计算断面积
group_by(habitat, species) |> # 3. 按生境和物种分组
summarise(
n = n(),
mean_height = round(mean(height), 1),
total_ba = round(sum(basal_area), 4),
.groups = "drop"
) |>
arrange(habitat, desc(total_ba)) # 4. 排序
result6.5 tidyr:数据重塑
生态学数据经常需要在”长格式”和”宽格式”之间转换。
6.5.1 宽格式 → 长格式:pivot_longer()
# 宽格式数据:每个物种一列
wide_data <- tibble(
plot = paste0("P", 1:5),
马尾松 = c(12, 8, 0, 15, 6),
杉木 = c(5, 0, 10, 3, 8),
桉树 = c(0, 7, 4, 0, 2)
)
wide_data
# 转为长格式
long_data <- wide_data |>
pivot_longer(
cols = -plot, # 除了 plot 列,其他都转
names_to = "species", # 列名变成 species 列
values_to = "count" # 值变成 count 列
)
long_data6.5.2 长格式 → 宽格式:pivot_wider()
# 转回宽格式
long_data |>
pivot_wider(
names_from = species,
values_from = count
)
Note什么时候用长格式?什么时候用宽格式?
- 长格式:适合 ggplot2 绘图和大多数统计分析
- 宽格式:适合展示和人工查看,以及某些多元统计分析(如 PCA)
一般原则:存储和分析用长格式,展示用宽格式。
6.6 数据合并
研究中经常需要合并来自不同来源的数据:
# 样方环境数据
plot_env <- tibble(
plot_id = paste0("P", 1:10),
elevation = round(runif(10, 200, 800)),
slope = round(runif(10, 5, 35)),
aspect = sample(c("N", "S", "E", "W"), 10, replace = TRUE)
)
# 将环境数据合并到调查数据
survey_full <- survey |>
left_join(plot_env, by = "plot_id")
head(survey_full)常用的合并方式:
| 函数 | 说明 |
|---|---|
left_join(x, y) |
保留 x 的所有行,匹配 y 的列 |
right_join(x, y) |
保留 y 的所有行 |
inner_join(x, y) |
只保留两边都有的行 |
full_join(x, y) |
保留所有行 |
6.7 实践:物种调查数据整理
综合运用本章所学,完成以下数据处理任务:
# 任务:生成一份各样方的物种多样性报告
diversity_report <- survey |>
filter(!is.na(height)) |> # 去除缺失值
left_join(plot_env, by = "plot_id") |> # 合并环境数据
group_by(plot_id, habitat, elevation) |> # 按样方分组
summarise(
n_individuals = n(), # 个体数
n_species = n_distinct(species), # 物种数
mean_height = round(mean(height), 1), # 平均株高
max_height = max(height), # 最大株高
.groups = "drop"
) |>
arrange(desc(n_species))
diversity_report6.8 课后练习
- 使用
iris数据集,用 dplyr 计算每个物种的花瓣长度和宽度的平均值 - 将
iris数据集转换为长格式(4 个测量值变成一列) - 筛选出花萼长度大于 6 的记录,按物种分组统计数量
- 创建一个数据处理流水线:筛选 → 新增列(花瓣面积 = 长 × 宽)→ 分组汇总 → 排序
- 将代码保存为
.qmd文件,渲染为 HTML 后提交到 GitHub