「R」数据操作(八):dplyr 的 do, do, do

2020-07-06 17:04:19 浏览数 (2)

关于dplyr的基本操作我已经写过很多笔记了,不再赘述,这篇文章重点介绍 dplyr 的一个函数 do() 的用法。

data.table类似,dplyr也提供了do()函数来对每组数据进行任意操作。

例如将diamondscut分组,每组都按log(price) ~ carat拟合一个线性模型。和data.table不同的是,我们需要为操作指定一个名称,以便将结果存储在列中。而且do()表达式不能直接在分组数据的语义下计算 ,我们需要使用.来表示数据。

代码语言:javascript复制
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()之前的代码:

代码语言:javascript复制
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

0 人点赞