【问题标题】:Fast way to find min in groups after excluding observations using R使用 R 排除观察后在组中找到最小值的快速方法
【发布时间】:2017-10-12 15:33:44
【问题描述】:

我需要在一个非常大的数据集(有很多组)上执行类似于下面的操作,并在某处读取使用 .SD 的速度很慢。有没有更快的方法来执行以下操作?

更准确地说,我需要创建一个新列,其中包含在排除该组中的观察子集之后每个组的最小值(类似于 Excel 中的 minif)。

library(data.table)
dt <- data.table(valid = c(0,1,1,0,1),
                   a = c(1,1,2,3,4),
                   groups = c("A", "A", "A", "B", "B"))

dt[, valid_min := .SD[valid == 1, min(a, na.rm = TRUE)], by = groups]

输出:

> test
valid a k valid_min
1:     0 1 A         1
2:     1 1 A         1
3:     1 2 A         1
4:     0 3 B         4
5:     1 4 B         4

更复杂的是,组可能没有有效条目,或者它们可能有多个有效但缺失的条目。我目前的代码是这样的:

dt <- data.table(valid = c(0,1,1,0,1,0,1,1),
                 a = c(1,1,2,3,4,3,NA,NA),
                 k = c("A", "A", "A", "B", "B", "C", "D", "D"))

dt[, valid_min := .SD[valid == 1, 
                      ifelse(all(is.na(a)), NA_real_, min(a, na.rm = TRUE))], by = k]

输出:

> dt
valid  a k valid_min
1:     0  1 A         1
2:     1  1 A         1
3:     1  2 A         1
4:     0  3 B         4
5:     1  4 B         4
6:     0  3 C        NA
7:     1 NA D        NA
8:     1 NA D        NA

【问题讨论】:

    标签: r performance data.table


    【解决方案1】:

    有……

    dt[dt[valid == 1 & !is.na(a), min(a), by=k], on=.(k), the_min := i.V1]
    

    这应该很快,因为对 min 的内部调用已针对组进行了优化。 (见?GForce。)

    【讨论】:

    • 谢谢!这正是我想要的:)
    【解决方案2】:

    我们可以用dplyr做同样的事情

    dt %>% 
      group_by(groups) %>% 
      mutate(valid_min = min(ifelse(valid == 1,
                                    a, NA),
                             na.rm = TRUE))
    

    这给出了:

      valid     a groups valid_min
      <dbl> <dbl>  <chr>     <dbl>
    1     0     1      A         1
    2     1     1      A         1
    3     1     2      A         1
    4     0     3      B         4
    5     1     4      B         4
    

    或者,如果您对保留“无效”行不感兴趣,我们可以执行以下操作:

    dt %>% 
      filter(valid == 1) %>% 
      group_by(groups) %>% 
      mutate(valid_min = min(a))
    

    看起来我提供了最慢的方法。将每种方法(使用称为df 的更大的复制数据框)与微基准测试进行比较:

    library(microbenchmark)
    library(ggplot2)
    mbm <- microbenchmark(
      dplyr.test = suppressWarnings(df %>% 
                                      group_by(k) %>% 
                                      mutate(valid_min = min(ifelse(valid == 1,
                                                                    a, NA),
                                                             na.rm = TRUE),
                                             valid_min = ifelse(valid_min == Inf,
                                                                NA,
                                                                valid_min))),
    
    
      data.table.test = df[, valid_min := .SD[valid == 1, 
                                              ifelse(all(is.na(a)), NA_real_, min(a, na.rm = TRUE))], by = k],
      GForce.test = df[df[valid == 1 & !is.na(a), min(a), by=k], on=.(k), the_min := i.V1]
    )
    
    autoplot(mbm)
    

    ...嗯,我试过了...

    【讨论】:

    • 谢谢!我会尝试一下。但是数据表不是基本上总是更快吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-07
    • 2019-09-20
    • 1970-01-01
    • 1970-01-01
    • 2018-11-13
    • 1970-01-01
    相关资源
    最近更新 更多