教程 ·

R语言tidyverse数据清洗入门:写给非编程背景研究者的实用指南

R语言tidyverse数据清洗入门教程:dplyr核心函数filter、select、mutate、group_by怎么用,管道符%>%怎么理解,缺失值和重复值怎么处理,宽表长表转换怎么做,面向没有编程背景的社科研究者。

很多社科背景的研究者习惯了 SPSS 的菜单式操作,第一次打开 R 看到一堆代码会本能地感到陌生。但 tidyverse 这套工具(R 里最流行的数据处理"方言")设计初衷正是让数据清洗代码读起来接近自然语言——这篇文章不讲编程原理,只讲你实际会用到的那几个核心函数。


为什么是 tidyverse

R 语言本身的基础语法(Base R)写数据清洗代码会比较繁琐、可读性较差。tidyverse 是一整套配合使用的 R 扩展包(最核心的是 dplyr 和 tidyr),它的设计哲学是:每一步操作都对应一个动词,多个动词像流水线一样串起来,代码读起来几乎像一句话

比如"筛选出年龄大于18岁的样本,再按性别分组计算平均收入",用 tidyverse 写出来是:

data %>%
  filter(age > 18) %>%
  group_by(gender) %>%
  summarise(mean_income = mean(income, na.rm = TRUE))

即使完全不懂 R,这几行代码也基本能"读"出它在做什么——这正是 tidyverse 相比传统编程语法对初学者更友好的地方。


管道符 %>% 怎么理解

%>%(或较新版本 R 里的原生管道符 |>)是 tidyverse 里最容易让人困惑、但理解之后会觉得"原来这么简单"的符号。

它的作用就是"把左边的结果,作为右边函数的第一个参数传进去"。可以把它想象成工厂流水线的传送带——数据从上一道工序"传送"到下一道工序,不需要每次都手动接住再传进去。

没有管道符的写法(需要一层层嵌套,从内往外读,很反直觉):

summarise(group_by(filter(data, age > 18), gender), mean_income = mean(income, na.rm = TRUE))

有管道符的写法(从上往下读,符合正常的思考顺序:先筛选,再分组,再汇总):

data %>%
  filter(age > 18) %>%
  group_by(gender) %>%
  summarise(mean_income = mean(income, na.rm = TRUE))

一旦理解了"%>% 就是把上一步的结果传给下一步",剩下要学的就只是每个动词函数具体做什么。


dplyr 核心函数:数据清洗最常用的几个动词

dplyr 是 tidyverse 里专门处理"表格数据"(行和列组成的数据框)的核心包,日常数据清洗 80% 的操作可以靠下面这五个函数完成:

1. filter():筛选行

按条件筛选出符合要求的观测(行),相当于 SPSS 里的"选择个案"。

# 筛选出年龄大于等于18且性别为女性的样本
data %>% filter(age >= 18, gender == "女")

2. select():选择列

从很多变量里选出你需要的几列,或者反过来剔除不需要的列。

# 只保留 id、age、income 三列
data %>% select(id, age, income)

# 剔除 remark 这一列,保留其他所有列
data %>% select(-remark)

3. mutate():新增或修改变量

创建新变量,或者对已有变量做转换,相当于 SPSS 里的"计算变量"。

# 新增一个"是否成年"的变量,同时把收入取对数
data %>% mutate(
  is_adult = ifelse(age >= 18, "是", "否"),
  log_income = log(income)
)

4. group_by() + summarise():分组汇总

先按某个(或某几个)变量分组,再对每组分别计算汇总统计量,相当于 SPSS 里的"分类汇总"或数据透视表的核心逻辑。

# 按性别分组,分别计算平均年龄和样本量
data %>%
  group_by(gender) %>%
  summarise(mean_age = mean(age, na.rm = TRUE), n = n())

5. arrange():排序

按某个变量对行重新排序,默认升序,加 desc() 变成降序。

data %>% arrange(desc(income))

缺失值处理

R 里缺失值用 NA 表示。tidyverse 处理缺失值最常用的几种方式:

识别缺失值

# 查看每一列缺失值的数量
data %>% summarise(across(everything(), ~ sum(is.na(.))))

剔除含缺失值的行

# 剔除任何变量存在缺失的行
data %>% drop_na()

# 只针对某个特定变量存在缺失的行做剔除
data %>% drop_na(income)

缺失值填补

# 用均值填补 income 的缺失值
data %>% mutate(income = ifelse(is.na(income), mean(income, na.rm = TRUE), income))

需要提醒的是:均值填补只是最基础的处理方式,会在一定程度上人为压缩数据的真实变异,实际研究中是否适合填补、用什么方法填补(如多重插补 Multiple Imputation),需要结合缺失机制(完全随机缺失/随机缺失/非随机缺失)审慎判断,不能不加说明地直接填补了事。


重复值处理

# 查看是否存在完全重复的行
data %>% duplicated() %>% sum()

# 剔除完全重复的行
data %>% distinct()

# 按某个关键变量(如身份证号/被试编号)判断重复,只保留第一次出现的记录
data %>% distinct(id, .keep_all = TRUE)

宽表和长表转换

问卷类数据经常需要在"宽表"(每个被试一行,每道题一列)和"长表"(每一行只对应一个被试在一道题上的一次作答)之间转换,尤其是在做重复测量方差分析或者绘制某些图表时。tidyr 包里的两个函数专门处理这个:

宽表转长表:pivot_longer()

# 把 T1、T2、T3 三个时间点的测量值列,转换成"时间点"和"测量值"两列
data %>%
  pivot_longer(cols = c(T1, T2, T3), names_to = "time", values_to = "score")

长表转宽表:pivot_wider()

# 反过来,把长表按时间点展开成多列
data %>%
  pivot_wider(names_from = time, values_from = score)

一个完整清洗流程示例

把上面的函数串起来,一个典型的数据清洗流程大致是这样:

library(tidyverse)

data_clean <- data %>%
  filter(age >= 18) %>%                      # 剔除未成年样本
  distinct(id, .keep_all = TRUE) %>%          # 按被试编号去重
  drop_na(income, education) %>%              # 剔除关键变量缺失的行
  mutate(
    log_income = log(income),                 # 新增对数收入变量
    age_group = ifelse(age < 35, "青年", "中老年")  # 新增年龄分组变量
  ) %>%
  select(id, age, age_group, income, log_income, education, gender)  # 只保留需要的列

这几行代码从上到下读下来,几乎就是"筛选成年样本,按编号去重,剔除关键变量缺失的记录,计算对数收入和年龄分组,最后只保留需要的几列"这句话本身——这正是 tidyverse 相比传统代码风格对研究者更友好的地方。


用 ChatSRS 辅助

不需要自己记住函数名和语法,直接用自然语言描述清洗需求即可:

"帮我用 R 语言清洗这份数据:剔除年龄小于18岁的样本,按被试编号去重,剔除收入和教育程度缺失的记录,新增一个按年龄分组的变量(35岁以下为青年,35岁及以上为中老年)。"

AI 会自动生成对应的 tidyverse 代码并执行,输出清洗后的数据以及清洗过程的说明,即使你完全不熟悉 R 语法也能看懂每一步做了什么。


适合人群

心理学、教育学、管理学、社会学等学科中,需要处理问卷或实验数据、又希望摆脱 SPSS 菜单操作局限(比如需要批量处理、可重复执行的清洗流程)的学位论文或期刊投稿研究者,都适合入门 R 的 tidyverse 数据清洗。


常见 FAQ

Q:完全没有编程基础,学 tidyverse 会不会很难?

A:tidyverse 相比传统编程语法已经是对初学者最友好的选择之一,核心难点其实只有两个:理解管道符 %>% 的含义,以及记住 filter/select/mutate/group_by/summarise 这几个高频函数分别做什么。建议先从这几个基础函数的组合使用练起,不需要一开始就追求"精通 R",能完成日常数据清洗需求就已经足够实用。

Q:SPSS 能做的数据清洗,是不是 R 都能做,有必要换吗?

A:SPSS 菜单操作在做单次、简单的清洗时确实更直观;但当清洗流程比较复杂、需要重复执行(比如换一批新数据要重新走一遍同样的清洗步骤)、或者需要清晰记录每一步处理逻辑供审稿人核查时,R 代码的可重复性和透明度优势会更明显。两者并不互斥,很多研究者会根据具体任务灵活选择。

Q:mutate() 新增变量和 SPSS 的"计算变量"是一回事吗?

A:概念上是一回事,都是基于已有变量通过某种运算规则生成新变量。区别在于 mutate() 可以在一次调用里同时新增多个变量、且能直接引用同一步骤里刚刚新增的变量继续计算,写法比 SPSS 逐个点选"计算变量"对话框更紧凑,尤其在需要新增多个衍生变量时效率更高。


本文首发于 ChatSRS 官方博客。如有问题或反馈,欢迎在 ChatSRS 站内【用户中心 -> 帮助与反馈】联系我们。