2017-10-12 99 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

相關問題