关于dplyr的基本操作我已经写过很多笔记了,不再赘述,这篇文章重点介绍 dplyr
的一个函数 do()
的用法。
与data.table
类似,dplyr
也提供了do()
函数来对每组数据进行任意操作。
例如将diamonds
按cut
分组,每组都按log(price) ~ carat
拟合一个线性模型。和data.table
不同的是,我们需要为操作指定一个名称,以便将结果存储在列中。而且do()
表达式不能直接在分组数据的语义下计算 ,我们需要使用.
来表示数据。
data("diamonds", package = "ggplot2")
models = diamonds %>%
group_by(cut) %>%
do(lmod = lm(log(price) ~ carat, data = .))
models
#> Source: local data frame [5 x 2]
#> Groups: <by row>
#>
#> # A tibble: 5 x 2
#> cut lmod
#> * <ord> <list>
#> 1 Fair <S3: lm>
#> 2 Good <S3: lm>
#> 3 Very Good <S3: lm>
#> 4 Premium <S3: lm>
#> 5 Ideal <S3: lm>
注意结果创建了一个新列,该列不是典型的原子向量,每个元素都是模型的结果,包含线性回归对象的列表。我们可以通过索引来提取模型结果:
代码语言:javascript复制models$lmod[[1]]
#>
#> Call:
#> lm(formula = log(price) ~ carat, data = .)
#>
#> Coefficients:
#> (Intercept) carat
#> 6.78 1.25
在需要完成高度定制的操作时,do()的优势非常明显。下面举例。
假如我们需要分析toy_tests数据,要对每种产品的质量和耐久性进行汇总。如果只需要样本数最多的3个测试记录,并且每个产品的质量和耐久性是经样本数加权的平均数,下面是做法。
代码语言:javascript复制toy_tests %>%
group_by(id) %>%
arrange(desc(sample)) %>%
do(head(., 3)) %>%
summarise(
quality = sum(quality * sample) / sum(sample),
durability = sum(durability * sample) / sum(sample)
)
#> # A tibble: 2 x 3
#> id quality durability
#> <chr> <dbl> <dbl>
#> 1 T01 9.32 9.38
#> 2 T02 9.04 8.34
为了查看中间结果,可以运行do()
之前的代码:
toy_tests %>%
group_by(id) %>%
arrange(desc(sample))
#> # A tibble: 8 x 6
#> # Groups: id [2]
#> id date sample quality durability ym
#> <chr> <int> <int> <int> <int> <chr>
#> 1 T01 20160405 180 9 10 201604
#> 2 T01 20160302 150 10 9 201603
#> 3 T01 20160502 140 9 9 201605
#> 4 T01 20160201 100 9 9 201602
#> 5 T02 20160403 90 9 8 201604
#> 6 T02 20160502 85 10 9 201605
#> 7 T02 20160303 75 8 8 201603
#> 8 T02 20160201 70 7 9 201602