【问题标题】:How to use R's {collapse} package to achieve a correct fgroup_by() |> ftransform() output?如何使用 R 的 {collapse} 包来实现正确的 fgroup_by() |> ftransform() 输出?
【发布时间】:2021-10-26 11:30:05
【问题描述】:

{collapse} 是一个R 包,可以加快数据操作和描述性统计的处理时间。一些功能intentionally echoes {dplyr}。例如,比较以下dplyr 代码与collapse 代码。它们在语法上非常相似,并且产生相同的输出。

library(ggplot2)
library(dplyr, warn.conflicts = FALSE)
library(collapse, warn.conflicts = FALSE)
#> collapse 1.6.5, see ?`collapse-package` or ?`collapse-documentation`
#> Note: stats::D  ->  D.expression, D.call, D.name

using_dplyr <- 
  mpg |>
  group_by(manufacturer) |>
  summarise(mean_hwy = mean(hwy))

using_collapse <- 
  mpg |>
  collapse::fgroup_by(manufacturer) |>
  collapse::fsummarise(mean_hwy = mean(hwy))

identical(using_collapse, using_dplyr)
#> [1] TRUE

但是{collapse} 更快

bench::mark(dplyr = 
              mpg |>
              group_by(manufacturer) |>
              summarise(mean_hwy = mean(hwy)),
            
            collapse = 
              mpg |>
              fgroup_by(manufacturer) |>
              fsummarise(mean_hwy = mean(hwy))) |>
  autoplot()

reprex package (v2.0.0) 于 2021 年 8 月 26 日创建


我的问题:
而以下表达式是类似的并且有效:
group_by() |&gt; summarise() = fgroup_by() |&gt; fsummrise(),
以下类比不起作用:
group_by() |&gt; mutate() |&gt; != fgroup_by() |&gt; ftransform()。 (ftransform()collapse 等价于 dplyr::mutate())。

证明问题
让我们用两种等效的语法来显示相同​​的管道:

library(ggplot2)
library(dplyr, warn.conflicts = FALSE)
library(collapse, warn.conflicts = FALSE)
#> collapse 1.6.5, see ?`collapse-package` or ?`collapse-documentation`
#> Note: stats::D  ->  D.expression, D.call, D.name

is_bigger_than_mean <- function(x) {
  x > mean(x)
}

## dplyr syntax
mutate_using_dplyr <- 
  mpg |>
  select(manufacturer, hwy) |>
  group_by(manufacturer) |>
  mutate(hwy_bigger_than_mean = is_bigger_than_mean(hwy))

## collapse syntax
mutate_using_collapse <- 
  mpg |>
  fselect(manufacturer, hwy) |>
  fgroup_by(manufacturer) |>
  ftransform(hwy_bigger_than_mean = is_bigger_than_mean(hwy))

比较hwy_bigger_than_mean列中的结果

mutate_using_dplyr  ## correct
#> # A tibble: 234 x 3
#> # Groups:   manufacturer [15]
#>    manufacturer   hwy hwy_bigger_than_mean
#>    <chr>        <int> <lgl>               
#>  1 audi            29 TRUE                
#>  2 audi            29 TRUE                
#>  3 audi            31 TRUE                
#>  4 audi            30 TRUE                
#>  5 audi            26 FALSE               
#>  6 audi            26 FALSE               
#>  7 audi            27 TRUE                
#>  8 audi            26 FALSE               
#>  9 audi            25 FALSE               
#> 10 audi            28 TRUE                
#> # ... with 224 more rows

mutate_using_collapse ## incorrect
#> # A tibble: 234 x 3
#>    manufacturer   hwy hwy_bigger_than_mean
#>  * <chr>        <int> <lgl>               
#>  1 audi            29 TRUE                
#>  2 audi            29 TRUE                
#>  3 audi            31 TRUE                
#>  4 audi            30 TRUE                
#>  5 audi            26 TRUE                
#>  6 audi            26 TRUE                
#>  7 audi            27 TRUE                
#>  8 audi            26 TRUE                
#>  9 audi            25 TRUE                
#> 10 audi            28 TRUE                
#> # ... with 224 more rows
#> 
#> Grouped by:  manufacturer  [15 | 16 (11)]

reprex package (v2.0.0) 于 2021 年 8 月 26 日创建

造成这种差异的原因是什么?是否有可能实现正确的输出,使mutate_using_collapse 提供与mutate_using_dplyr 相同的输出?

注意:类似问题讨论了类似问题here

【问题讨论】:

  • 根据文档:“请注意,与 dplyr::mutate 不同,ftransform 本身不会对分组数据帧执行任何操作。” — 我的猜测是该软件包通过删除功能购买了更高的性能。
  • 刚读到这个问题。我认为我犯的一个错误是在文档中提及dplyr::mutate。顾名思义,ftransformbase::transform 的更快、更通用的替代品。从工程的角度来看,很难按组优化mutate 的功能,因为表达式可能是任意的,例如mutate(newcol = col1 - FUN(col2) + FUN2(col3)) requires FUN1` 和 FUN2 为每个组执行。一般来说,{collapse} 不会按组执行任何 R 函数,所有分组操作都是通过快速统计函数在 C++ 中实现的。
  • 就通用的“split-apply-combine”计算机制而言,我推荐data.table,它具有非常快速的机制,可以按组执行任意表达式。请注意,data.table 仅对其内部优化的功能达到非常高的速度,请参阅?GForce,并且这些优化中的大多数也仅可用于聚合。 {collapse} 的任务是提供类似的优化函数和一些可应用于向量矩阵和杂项的支持语法。表格数据,支持计量经济学所需的加权计算和数据转换。

标签: r dplyr


【解决方案1】:

正如 Konrad 所指出的,ftransform() 不是 mutate() 的一对一替代品,因为它的设计范围更受限制,默认情况下不尊重分组数据,主要是旨在与包中的一组受限“快速”功能一起使用。

您可以使用fmean() 函数来实现您的目标,但需要通过GRP() 函数明确告诉它使用分组数据。

另请注意,它不适用于新的基本 R 管道,您需要使用 magrittr 管道才能将分组数据用于函数调用。

library(ggplot2)
library(dplyr)
library(collapse)

mpg %>%
   fselect(manufacturer, hwy) %>%
   fgroup_by(manufacturer) %>%
   ftransform(hwy_bigger_than_mean = hwy > fmean(hwy, GRP(.), TRA = "replace")) 

# A tibble: 234 x 3
   manufacturer   hwy hwy_bigger_than_mean
 * <chr>        <int> <lgl>               
 1 audi            29 TRUE                
 2 audi            29 TRUE                
 3 audi            31 TRUE                
 4 audi            30 TRUE                
 5 audi            26 FALSE               
 6 audi            26 FALSE               
 7 audi            27 TRUE                
 8 audi            26 FALSE               
 9 audi            25 FALSE               
10 audi            28 TRUE                
# ... with 224 more rows

【讨论】:

  • 这很有帮助,谢谢。所以基本上我不能在ftransform() 中使用任何非collapse 函数,对吧?因为只有 collapse 函数有内置的分组参数。
  • 我的理解是,collapse 的目的是作为 dplyr 的附属品,而不是替代品。在崩溃可以加速计算的情况下,它提供了一些东西,否则期望您使用 dplyr。请注意,在这种情况下,这也适用于 B(代表介于)就像 R 中的 avesltfselect 的缩写形式,tfmftransform 的缩写形式。 mpg |&gt; slt(hwy, manufacturer) |&gt; tfm(hwy_bigger_than_mean = hwy &gt; B(hwy, manufacturer))
  • 这也有效:mpg %&gt;% slt(hwy, manufacturer) |&gt; fgroup_by(manufacturer) %&gt;% tfm(bigger = hwy &gt; B(hwy, GRP(.)))
  • 我仍然面临一些不一致的问题。考虑效用函数name_with_letter &lt;- function(x) { v &lt;- setNames(x, sample(letters, 1) ); collapse::qDF(v, "name_letter") }。然后运行管道:mpg %&gt;% fselect(manufacturer, hwy) %&gt;% fgroup_by(manufacturer) %&gt;% ftransform(new_col = map(.x = hwy, .f = ~name_with_letter(.x) )) %&gt;% fungroup() %&gt;% tidyr::unnest(new_col)。有效!
  • 所以我不确定我如何知道ftransform() 什么时候可以工作,什么时候不能工作。当涉及到非原生 collapse 函数时。
猜你喜欢
  • 2021-07-24
  • 1970-01-01
  • 2022-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多