【问题标题】:dplyr summarise() with special functions for edge casesdplyr summarise() 具有针对边缘情况的特殊功能
【发布时间】:2016-09-19 20:35:06
【问题描述】:

我想在 dplyr 中进行分组summarise() 操作,但如果遇到边缘情况,则应用不同的函数。

我有这样的计数数据。浓度和标准差的计算如下:

library(dplyr)
testdata <- data_frame(sample = sort(rep(1:3, 4)),
                   volume = rep(c(1e-1, 1e-1, 1e-2, 1e-2), 3),
                   count = c(400, 400, 40, 40, 0, 0, 0, 0, 400, 400, 400, 400))

testdata %>% 
  group_by(sample) %>% 
  summarise(concentration = sum(count) / sum(volume),
            sd   = sqrt(sum(count)))

但是,在进行计算时,仅包含值在 25-250 之间的计数。我可以通过以下方式实现:

testdata %>% 
  group_by(sample) %>%
  filter((count >= 25) & (count <= 250)) %>%
  summarise(concentration = sum(count) / sum(volume),
            sd   = sqrt(sum(count)))

但是样品 2 和 3 没有浓度。

每个组的边缘情况可以通过以下方式计算:

if (all(count <= 25)){
  summarise(concentration = 25 / min(volume),
            sd = NA)
}
else if (all(count >= 250)){
  summarise(concentration = 250 / max(volume),
            sd = NA)
}

可以将这种边缘情况集成到summarise() 函数中吗?

理想情况下,我还希望有一个标志来指示一个边缘情况,该情况在所有情况下都返回 result = "OK",但返回的边缘情况除外:

if (all(count <= 25)){
  summarise(concentration = 25 / min(volume),
            sd = NA,
            result = "LOW")
}
else if (all(count >= 250)){
  summarise(concentration = 250 / max(volume),
            sd = NA,
            result = "HIGH")
}

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    一种方法是使用ifelsesummarise 中的逻辑进行编码:

    library(dplyr)
    result <- testdata %>% group_by(sample) %>%
                           summarise(concentration = ifelse(all(count <= 25), 
                                                            25 / min(volume),
                                                            ifelse(all(count >= 250), 
                                                                   250 / max(volume), 
                                                                   sum(count) / sum(volume))),
                                     sd = ifelse(all(count <= 25), 
                                                 NA, 
                                                 ifelse(all(count >= 250), 
                                                        NA, 
                                                        sqrt(sum(count)))),
                                     result = ifelse(all(count <= 25), 
                                                     "LOW", 
                                                     ifelse(all(count >= 250),
                                                            "HIGH", 
                                                            "OK")))
    print(result)
    ### A tibble: 3 x 4
    ##  sample concentration       sd result
    ##   <int>         <dbl>    <dbl>  <chr>
    ##1      1          4000 29.66479     OK
    ##2      2          2500       NA    LOW
    ##3      3          2500       NA   HIGH
    

    更新方法

    另一种方法,希望更接近 OP 的要求,是定义一个函数:

    summarise.func <- function(count, volume) {
      if (all(count <= 25)) {
        concentration <- 25 / min(volume)
        sd <- NA
        result <- "LOW"
      } else if (all(count >= 250)) {
        concentration <- 250 / max(volume)
        sd <- NA
        result <- "HIGH"
      } else {
        concentration <- sum(count) / sum(volume)
        sd <- sqrt(sum(count))
        result <- "OK"
      }
      data.frame(concentration=concentration, sd=sd, result=result, stringsAsFactors=FALSE)
    }
    

    同时处理常规情况和边缘情况。关键是这个函数返回一个包含汇总结果的data.frame。然后,summarise 将创建一个列,该列是一个包含这些数据框的列表,然后可以是tidyr::unnested:

    library(dplyr)
    library(tidyr)
    result <- testdata %>% group_by(sample) %>%
                           summarise(csr=list(f(count, volume))) %>%
                           unnest(csr)
    print(result)
    ### A tibble: 3 x 4
    ##  sample concentration       sd result
    ##   <int>         <dbl>    <dbl>  <chr>
    ##1      1          4000 29.66479     OK
    ##2      2          2500       NA    LOW
    ##3      3          2500       NA   HIGH
    

    【讨论】:

    • 谢谢。这解决了这个问题,所以我要接受它。我想我正在寻找一个单独计算每个案例的浓度/标准差/结果的答案,而不是将每个边缘案例的逻辑嵌套在每个变量的计算逻辑中。
    • @Aaron:我的建议是按原样接受答案。这样,其他人(甚至可能是我)可以提供另一个更好且可以接受的答案。
    • 没问题。但我想我可能会尝试另一个问题,看看我是否可以更明确地将这个概念表达为一个问题。
    • @Aaron:如果可以,请编辑这个问题。我会更加努力地思考我是否能更接近你想要的(我想我明白这一点)。但是,没有任何承诺。我认为的问题是将分组与逻辑混为一谈。我们可能会尝试在 dplyr 之外执行此操作。
    • @Aaron:请查看我的更新,看看它是否更接近你想要的。
    猜你喜欢
    • 1970-01-01
    • 2021-09-27
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 2012-01-17
    • 1970-01-01
    • 2018-03-31
    • 1970-01-01
    相关资源
    最近更新 更多