Menu

R dplyr 入门教程:filter、select、mutate、summarize

dplyr 是什么、怎么安装,以及它的六个核心动词加上管道,如何把杂乱的数据框代码变成可读的流水线。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

dplyr 是什么

dplyr 是 R 中最流行的数据处理包,一套由少数几个动词构成的“数据语法”。每个动词都是一个函数:接收一个数据框,只做一件事(保留部分行、添加一列、计算分组汇总),然后返回一个新的数据框。因为每个动词的形状都一样,数据框进,数据框出,所以它们能用管道拼接成流水线,从上往下读就像一份菜谱。dplyr 是 tidyverse 的核心,tidyverse 是一系列采用同样设计的包(tidyr、ggplot2、readr)。

dplyr 能做的一切,base R 也能做。下面是一个纯 base R 写的小分析:把内置的 mtcars 数据筛选为 4 缸汽车,计算一个新列,再按档位数求平均值。这段代码可以运行:

它能用,而且是很好的 R 代码。但注意,整个逻辑被分散在方括号索引、一次 $ 赋值和一个公式里。同样分析的 dplyr 版本:

library(dplyr)

mtcars |>
    filter(cyl == 4) |>
    mutate(kml = mpg * 0.425) |>
    group_by(gear) |>
    summarize(avg_kml = round(mean(kml), 1))

四个动词,顺序和你口头讲解时一模一样。可读性就是 dplyr 最大的卖点,在二十步的流水线上,这一点是决定性的。

本页的 dplyr 代码片段是静态的,因为这里的编辑器只能运行 base R;想运行它们,就按下面的方法在你自己的电脑上安装 dplyr。

安装和加载

安装一次,然后在每个用到它的脚本中加载:

install.packages("dplyr")   # once, per machine
library(dplyr)              # every script

也可以改为运行 install.packages("tidyverse"),它会把 dplyr 和它的兄弟包一起装上。dplyr 加载时会警告说它屏蔽了 stats::filter 和 stats::lag,这是正常现象,不是错误。

六个核心动词

每个动词都把数据框作为第一个参数,列名直接裸写,不加引号,也不加 df$ 前缀。

filter() 保留符合条件的行:

mtcars |> filter(mpg > 25)
mtcars |> filter(cyl == 4, hp < 70)   # comma = AND

select() 保留列,可以按名称、范围或辅助函数选择:

mtcars |> select(mpg, cyl, hp)
mtcars |> select(mpg:hp)              # a range of adjacent columns
mtcars |> select(starts_with("d"))    # disp, drat

mutate() 添加或变换列:

mtcars |> mutate(kml = mpg * 0.425, heavy = wt > 3.5)

arrange() 对行排序,把列包在 desc() 里就是降序:

mtcars |> arrange(desc(mpg))

summarize() 把多行折叠成一行汇总,而 group_by() 让它改为按组折叠:

mtcars |>
    group_by(cyl) |>
    summarize(n = n(), avg_mpg = mean(mpg))

group_by() 本身看不出任何效果,它只是给数据框打上标记,让接下来的 summarize()(或 mutate())按组进行。每个动词在本章都有完整的文档:筛选行、添加列、排序和分组汇总。

用管道串联动词

管道 |> 把它前面的值作为第一个参数传给后面的函数:x |> f(y) 就是 f(x, y)。因为每个 dplyr 动词都接收并返回数据框,所以动词可以无限串下去:

mtcars |>
    filter(hp > 100) |>
    mutate(kml = mpg * 0.425) |>
    group_by(cyl) |>
    summarize(cars = n(), avg_kml = round(mean(kml), 1)) |>
    arrange(desc(avg_kml))

大声读出来:取 mtcars,保留马力超过 100 的汽车,添加一列每升公里数,按气缸数分组,统计每组数量并求平均值,再按平均值排序。没有中间变量,也没有嵌套。较早的代码用 magrittr 包的 %>% 而不是 |>,在 dplyr 中两者可以互换;|>(R 4.1 及以上版本内置)的讲解见管道文档。

count() 和 n():计数助手

计数太常用了,所以 dplyr 提供了快捷方式。n() 给出当前组的行数(只能在 summarize() 或 mutate() 内部使用),而 count() 把 group_by() + summarize(n = n()) 这一整套合并成一次调用:

mtcars |> count(cyl)                    # rows per cyl value
mtcars |> count(cyl, gear, sort = TRUE) # two groupers, biggest first

如果你发现自己在写 group_by(x) |> summarize(n = n()),就把它换成 count(x)。

关于 tibble

dplyr 动词经常返回 tibble,它是 tidyverse 版本的数据框。它本身就是数据框(任何接受数据框的地方都接受 tibble),只是打印更友好:只显示前 10 行和放得下的列,每个列名下方还会显示类型。有两点区别值得了解:tibble 从不使用行名(所以 mtcars |> as_tibble() 会丢掉汽车名称,tidyverse 希望标识符放在真正的列里),而且单层方括号索引总是返回 tibble,而不会有时退化成向量。日常使用中这两点都不会让你意外;只是当 str() 显示 tbl_df 时不用慌。

要点总结

  • dplyr 是一套语法:六个动词,每个对数据框只做一件事,用管道串起来。
  • filter() 选行,select() 选列,mutate() 添加列,arrange() 排序,group_by() + summarize() 做聚合。
  • x |> f(y) 就是 f(x, y):流水线按事情发生的顺序从上往下读。
  • count() 和 n() 能满足大部分计数需求。
  • base R 全都能做;一旦流水线变长,dplyr 在可读性上胜出。

下一篇:深入讲解筛选和取子集,包括 base R 的方括号写法,以及 dplyr 的 filter() 适合用在哪里。

常见问题

R 中的 dplyr 是什么?

dplyr 是使用最广泛的 R 数据框处理包。它提供一小组动词:filter()、select()、mutate()、arrange()、summarize()、group_by(),每个动词对数据框只做一件事,再用管道串起来,形成可读的流水线。它是 tidyverse 的一部分。

怎么安装 dplyr?

运行一次 install.packages("dplyr"),然后在每个用到它的脚本开头写 library(dplyr)。也可以改为安装 tidyverse,一次就能装好 dplyr 和它的兄弟包(tidyr、ggplot2、readr)。

我需要 dplyr 吗,还是 base R 就够了?

dplyr 能做的,base R 都能做:取子集、aggregate()、order()。base R 值得掌握,因为它无需任何依赖、到处都能用。当流水线变长时,dplyr 的优势就体现出来了:串起来的五个动词读起来像一句话,而等价的 base R 代码读起来像层层嵌套的括号谜题。

dplyr 中的 summarize 和 summarise 有什么区别?

没有区别。它们是同一个函数,只是美式和英式拼写不同;dplyr 两个都导出了。你的团队用哪个就用哪个,保持一致即可。

Coddy 编程语言插图

和 Coddy 一起学编程

开始