我如何仅总结一部分表格?

Kon*_*lph 20 r dplyr

我有两个相关的用例,我需要总结一个表的部分,以类似的方式指定filter.

简而言之,我想要这样的东西:

iris %>%
    use_only(Species == 'setosa') %>%
    summarise_each(funs(sum), -Species) %>%
    mutate(Species = 'setosa_sum') %>%
    use_all()
Run Code Online (Sandbox Code Playgroud)

产生这个:

Source: local data frame [101 x 5]

   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1         250.3       171.4         73.1        12.3 setosa_sum
2           7.0         3.2          4.7         1.4 versicolor
3           6.4         3.2          4.5         1.5 versicolor
4           6.9         3.1          4.9         1.5 versicolor
5           5.5         2.3          4.0         1.3 versicolor
…
Run Code Online (Sandbox Code Playgroud)

因此,我不使用列的值进行分组,而是使用过滤条件对表的视图进行操作,而不会实际丢失表的其余部分(与过滤器不同).

我如何巧妙地实施use_only/ use_all更好的是,这个功能已经包含在内,dplyr我该如何使用它?

生成上面的结果当然很容易,但我需要为许多不同的情况做类似的事情,具有复杂和可变的过滤标准.

Dav*_*son 13

use_only通过将表的其余部分保存到全局选项dplyr_use_only_rest并将use_all其重新绑定在一起的方法实现了这一点.

use_only <- function(.data, ...) {
    if (!is.null(.data$.index)) {
        stop("data cannot already have .index column, would be overwritten")
    }
    filt <- .data %>%
        mutate(.index = row_number()) %>%
        filter(...)

    rest <- .data %>% slice(-filt$.index)
    options(dplyr_use_only_rest = rest)
    select(filt, -.index)
}

use_all <- function(.data, ...) {
    rest <- getOption("dplyr_use_only_rest")
    if (is.null(rest)) {
        stop("called use_all() without earlier use_only()")
    }
    options(dplyr_use_only_rest = NULL)
    bind_rows(.data, rest)
}
Run Code Online (Sandbox Code Playgroud)

我认识到设置全局选项并不是理想的函数式编程设计,但我认为还有另一种方法可以确保数据帧的其余部分不受任何中间函数的影响.向对象添加额外属性将无法使用诸如do或之类的函数summarize.

在此刻,

iris %>%
    use_only(Species == 'setosa') %>%
    summarise_each(funs(sum), -Species) %>%
    mutate(Species = 'setosa_sum') %>%
    use_all()
Run Code Online (Sandbox Code Playgroud)

根据需要返回:

   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1         250.3       171.4         73.1        12.3 setosa_sum
2           7.0         3.2          4.7         1.4 versicolor
3           6.4         3.2          4.5         1.5 versicolor
4           6.9         3.1          4.9         1.5 versicolor
5           5.5         2.3          4.0         1.3 versicolor
...
Run Code Online (Sandbox Code Playgroud)

可以代替使用任何中间步骤summarize_eachmutate(do,filter,等),他们只会发生在指定的行.你甚至可以添加或删除列(其余部分将用NAs 填充).


edd*_*ddi 13

我认为您搜索函数以满足特定语法的方法过于严格.这就是我要做的事情data.table(我不确定是否dplyr允许这样的变量行,我知道它已经是FR了一段时间):

library(data.table)
dt = as.data.table(iris)

dt[, if (Species == 'setosa') lapply(.SD, sum) else .SD, by = Species]
#        Species Sepal.Length Sepal.Width Petal.Length Petal.Width
#  1:     setosa        250.3       171.4         73.1        12.3
#  2: versicolor          7.0         3.2          4.7         1.4
#  3: versicolor          6.4         3.2          4.5         1.5
#  4: versicolor          6.9         3.1          4.9         1.5
#  5: versicolor          5.5         2.3          4.0         1.3
# ---                                                             
Run Code Online (Sandbox Code Playgroud)

您还可以[Species == 'setosa', Species := 'setosa_sum']在最后添加以修改名称.应该直接扩展到多个标准/任何功能.

  • 嗯,通过这个论点的延伸,你应该留在基地.R的方式是使用任何和所有软件包,以最简单和最快的形式实现您想要的 (5认同)
  • @BrodieG"可以"与"应该是"不一样.这是一个非常难以理解的烂摊子.事实上,我不是开始使用data.table语法的忠实粉丝,而是以这种方式将它与dplyr管道相结合......没有.我最重要的目标是编写可理解的,可维护的代码(尽可能)显然没有错误.使用这种卷积是适得其反的.正如我之前提到的那样,通过临时变量有大量可行的解决方案.制作*可读*解决方案就是我追求的目标. (4认同)
  • 我不确定你的意思是什么 - (a)`dplyr`和data.tables一起工作,而(b)`data.table`有`setDT`和`setDF`函数来回传递` data.frame`和`data.table`到位. (2认同)
  • 听起来你想要为流水线操作而管道 - 这显然是你的选择,但我认为这不是一个明智的方法.而且这个选项与手动拆分和拼接在一起的根本不同.无论如何,你有选择,可以选择做任何你想做的事情,我所说的只是你认为你所拥有的任何承诺完全是虚构的. (2认同)

ber*_*ant 5

您可以创建一个新列来分组:

iris %>%
  mutate( group1 = ifelse(Species == "setosa", "", row_number()))  %>%
  group_by( group1, Species ) %>%
  summarise_each(funs(sum), -Species, -group1) %>%
  ungroup() %>%
  select(-group1)
Run Code Online (Sandbox Code Playgroud)

更新 - 作为更一般的解决方案

library(lazyeval)

use_only_ <- function(x, condition, ...) {
  condition <- as.lazy(condition, parent.frame())
  mutate_(x, .group = condition) %>% 
    group_by_(".group", ...)
}

use_only <- function(x, condition, ...) {
  use_only_(x, lazy(condition), ...)
}

use_all <- function(x) {
  ungroup(x) %>%
    select(- .group)
}
Run Code Online (Sandbox Code Playgroud)

use_only在数据框和调用环境的上下文中使用任何条件.在这种情况下:

iris %>%
  use_only( ifelse(Species == "setosa", "", row_number()), "Species") %>%
  summarise_each(funs(sum), -Species, -.group) %>%
  use_all()
Run Code Online (Sandbox Code Playgroud)

use_only_可与式或字符串来使用.例如:

condition <- ~ifelse(Species == "setosa", "", row_number())
Run Code Online (Sandbox Code Playgroud)

要么

condition <- "ifelse(Species == 'setosa' , "", row_number())"
Run Code Online (Sandbox Code Playgroud)

并致电:

iris %>%
  use_only_(condition, "Species") %>%
  summarise_each(funs(sum), -Species, -.group) %>%
  use_all()
Run Code Online (Sandbox Code Playgroud)

use_onlyuse_all调用之间进行变异时,必须注意仅更改标记组内的值.