教程 ·
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 站内【用户中心 -> 帮助与反馈】联系我们。