2017-10-12 84 views
1

我需要在非常大的数据集(包含多个组)的情况下执行类似于以下的操作,并在某处使用.SD缓慢读取。有没有更快的方法来执行以下操作?使用R排除观察值后快速找到分组的最小值

更准确地说,我需要创建一个新列,其中包含每个组的最小值,排除该组中的某个观察子集(类似于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 

回答

2

有...

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

这应该是快速的,因为内部调用min是针对组优化的。 (见?GForce。)

+1

谢谢!这正是我一直在寻找的:) – adamski

1

我们可以通过做同样的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 

另外,如果你对k不感兴趣eeping“非有效”行,我们可以做到以下几点:

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) 

enter image description here

...嗯,我想...

+1

谢谢!我会尝试一下。但是不是数据表基本上总是更快? – adamski

相关问题