【问题标题】:dplyr conditional summarise functiondplyr 条件汇总函数
【发布时间】:2018-10-06 10:13:24
【问题描述】:

我有这种情况,我需要基于条件的不同摘要函数。 例如,使用 iris,假设出于某种原因,如果物种是 setosa,我想要花瓣宽度的总和,否则我想要花瓣宽度的平均值。

天真地,我用 case_when 写了这个,它不起作用:

iris <- tibble::as_tibble(iris)

 iris %>% 
  group_by(Species) %>% 
  summarise(pwz = case_when(
    Species == "setosa" ~ sum(Petal.Width, na.rm = TRUE),
    TRUE                ~ mean(Petal.Width, na.rm = TRUE)))

summarise_impl(.data, dots) 中的错误: pwz 列的长度必须为 1(汇总值),而不是 50

我最终找到了类似的东西,使用每种方法进行总结,然后在变异中挑选我真正想要的一种:

iris %>% 
  group_by(Species) %>% 
  summarise(pws = sum(Petal.Width, na.rm = TRUE),
            pwm = mean(Petal.Width, na.rm = TRUE)) %>% 
  mutate(pwz = case_when(
    Species == "setosa" ~ pws,
    TRUE                ~ pwm)) %>% 
  select(-pws, -pwm)

但是,创建所有这些汇总值并在最后只选择一个似乎有点尴尬,尤其是当我的真实 case_when 复杂得多时。我不能在摘要中使用 case_when 吗?我的语法错了吗?任何帮助表示赞赏!

编辑:我想我应该指出我有多个条件/函数(假设我有一些需要均值、总和、最大值、最小值或其他摘要的变量,具体取决于变量)。

【问题讨论】:

  • 听起来真正的问题可能是您的数据不是“整洁”的格式。根据其他列值对同一列中的值执行不同的汇总是非常奇怪的。你不能像那样使用case_when,因为它是一个矢量化函数,所以它不会崩溃(你一次只能取一个值的总和/平均值)。
  • 它是长格式 - 不同变量随时间(每天)按地区观察的环境数据。我正在创建每周摘要,但是,例如,您需要添加降雨量才能获得该周的总降雨量,但对于温度,则取一周内的平均值。所以这可能很奇怪,但对这个数据集来说是有意义的。这是关于它是一个非折叠矢量化函数的有用信息 - 这告诉我为什么我的第一次尝试没有奏效,谢谢。

标签: r dplyr


【解决方案1】:

您可以拆分您的data.frame,然后使用map2_dfr 在每个部分上应用不同的函数并将结果重新拼接在一起:

library(tidyverse) # purrr & dplyr
iris %>%
  arrange(Species=="setosa") %>%
  split(.,.$Species=="setosa") %>%
  map2_dfr(c(mean,sum),~.x %>% group_by(Species) %>% summarize_at("Petal.Width",.y))

# # A tibble: 3 x 2
# Species Petal.Width
#       <fctr>       <dbl>
# 1 versicolor       1.326
# 2  virginica       2.026
# 3     setosa      12.300

【讨论】:

  • 哦,我想如果我能更好地理解 purrr 函数,这对我来说可能会很好用。我实际上正在做一大堆 dplyr 编程/新功能,我不知道我会提前获得哪些物种(在我的代码中,环境变量),所以我不能硬编码任何东西。我有一个查找表,我敢打赌我可以用它来适当地拆分和映射以进行摘要。 purrr里面的函数我还没用过,不过我试试看,非常感谢!
  • 如果您了解lapplyMap,您很快就会了解purrr::map 家族。要参数化我的函数,只需将“setosa”替换为 x,将“Petal.Width”替换为 y。
【解决方案2】:

data.table 很容易做到这一点

library(data.table)
iris2 <- as.data.table(iris)

iris2[, if(Species == 'setosa') sum(Petal.Width) 
        else mean(Petal.Width)
      , by = Species]

更简洁,但可能不够清晰

iris2[, ifelse(Species == 'setosa', sum, mean)(Petal.Width)
      , by = Species]

dplyr 你可以做到

iris %>% 
  group_by(Species) %>% 
  summarise(pwz = if_else(first(Species == "setosa")
                          , sum(Petal.Width)
                          , mean(Petal.Width)))

注意:

我认为使用tidyr::spread“传播”您的数据可能更有意义,这样每天都有一个温度、降雨量等列。然后您可以按通常的方式使用summarise

【讨论】:

  • 我想过传播。我的功能是接受广泛的环境变量,并通过查找表找出汇总方法。我认为如果我tidyr::spread,我会更难跟踪可变数量的新列。我想我可能用我的可重复的例子简化了我的问题。我试图避免多个嵌套的if_else 语句(因此我首先尝试case_when),但它仍然在我正在尝试的事情上。谢谢!
  • @michdn 是的,我认为如果使用dplyr,关键是在您知道它们都相同时只使用first 来检查值。您当然可以在case_whenif_else 中使用first 函数
【解决方案3】:
data(iris)
library(dplyr)

sum_species <- c('setosa')

iris %>% 
   group_by(Species) %>% 
   summarise(pwz_sum = sum(Petal.Width, na.rm=T), 
             pwz_mean= mean(Petal.Width, na.rm=T)) %>% 
   ungroup() %>% 
   mutate(pwz = if_else(Species %in% sum_species, pwz_sum, pwz_mean))

【讨论】:

  • 啊,感谢您将变量拆分为列表(用于总和、均值等)的想法。我玩了一段时间,因为我有一个未知且可变数量的环境变量(我的数据)我在我的函数中总结。我仍然有一个问题,即我正在为所有这些摘要创建所有不同类型的摘要,尽管我可能只需要接受它作为中间步骤。
  • 您可以使用switch 创建一个新函数以进行汇总。比如:switch(Species, setosa = sum(...), species2 = mean(...), species3=foo(...), ...)
【解决方案4】:

为什么不先行级计算,再汇总?

iris %>% group_by(Species) %>% mutate(pwz = case_when(
      Species == "setosa" ~ sum(Petal.Width, na.rm = TRUE),
      TRUE                ~ mean(Petal.Width, na.rm = TRUE))) %>% 
      summarize(pwz= first(pwz))

# A tibble: 3 x 2
     Species    pwz
      <fctr>  <dbl>
1     setosa 12.300
2 versicolor  1.326
3  virginica  2.026

【讨论】:

  • 这对我来说实际上可能是最简单、最容易做的事情。当我第一次尝试时,我的 case_when 情况已经被半编码了。这非常简单,这很好,因为我将把这段代码传递给其他人。明天我有一个项目会议,我们将看看我团队中其他编码人员的想法。谢谢!
【解决方案5】:

如果你想把所有东西都放在汇总函数中,你总是可以做这样的事情。但这并不比您原来的解决方法复杂:

iris %>% 
  group_by(Species) %>% 
  summarise(pwz = 
    sum(Petal.Width, na.rm = TRUE)*
    (1/n()*mean(Species != "setosa") + 
     mean(Species == "setosa")))

【讨论】:

  • 哈,这很有创意。不过,我会同情必须在我之后维护我的代码的人。谢谢!
猜你喜欢
  • 2016-02-07
  • 1970-01-01
  • 2019-03-06
  • 2017-12-30
  • 1970-01-01
  • 2017-03-19
  • 2021-10-14
  • 1970-01-01
  • 2017-06-06
相关资源
最近更新 更多