О GForce в data.table 1.9.2

Я не знаю, как использовать GForce в data.table 1.9.2

Новая оптимизация: GForce. Вместо группировки данных местоположения групп передаются в сгруппированные версии sum и mean (gsum и gmean), которые затем вычисляют результат для всех групп за один последовательный проход через столбец для эффективности кеша. Кроме того, поскольку функция g * вызывается только один раз, нам не нужно искать способы ускорить вызов суммы или среднее количество повторений для каждой группы. `

при отправке следующего кода

DT <- data.table(A=c(NA,NA,1:3), B=c("a",NA,letters[1:3]))
DT[,sum(A,na.rm=TRUE),by= B]

Я получил это

    B V1
1:  a  1
2: NA  0
3:  b  2
4:  c  3

и при попытке DT[,sum(A,na.rm=FALSE),by= B] я получил

    B  V1
1:  a  NA
2:  NA NA
3:  b  2
4:  c  3

Объясняет ли это, что делает GForce, добавив параметр na.rm = TRUE/FALSE?

Спасибо большое!

Ответ 1

Это не связано с na.rm. То, что вы показываете, хорошо работало и раньше. Однако я могу понять, почему вы могли подумать об этом. Вот остальная часть того же пункта:

Examples where GForce applies now :
    DT[,sum(x,na.rm=),by=...]                       # yes
    DT[,list(sum(x,na.rm=),mean(y,na.rm=)),by=...]  # yes
    DT[,lapply(.SD,sum,na.rm=),by=...]              # yes
    DT[,list(sum(x),min(y)),by=...]                 # no. gmin not yet available
GForce is a level 2 optimization. To turn it off: options(datatable.optimize=1)
Reminder: to see the optimizations and other info, set verbose=TRUE

Вам не нужно ничего делать, это автоматическая оптимизация.

Вот пример 500 миллионов строк и 4 столбца (13 ГБ). Сначала создайте и проиллюстрируйте данные:

$ R
R version 3.0.2 (2013-09-25) -- "Frisbee Sailing"
Copyright (C) 2013 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

> require(data.table)
Loading required package: data.table
data.table 1.9.2  For help type: help("data.table")

> DT = data.table( grp = sample(1e6,5e8,replace=TRUE), 
                   a = rnorm(1e6),
                   b = rnorm(1e6),
                   c = rnorm(1e6))
> tables()
     NAME        NROW    MB COLS      KEY
[1,] DT   500,000,000 13352 grp,a,b,c    
Total: 13,352MB
> print(DT)
          grp          a            b          c
1e+00: 695059 -1.4055192  1.587540028  1.7104991
2e+00: 915263 -0.8239298 -0.513575696 -0.3429516
3e+00: 139937 -0.2202024  0.971816721  1.0597421
4e+00: 651525  1.0026858 -1.157824780  0.3100616
5e+00: 438180  1.1074729 -2.513939427  0.8357155
   ---                                          
5e+08: 705823 -1.4773420  0.004369457 -0.2867529
5e+08: 716694 -0.6826147 -0.357086020 -0.4044164
5e+08: 217509  0.4939808 -0.012797093 -1.1084564
5e+08: 501760  1.7081212 -1.772721799 -0.7119432
5e+08: 765653 -1.1141456 -1.569578263  0.4947304

Теперь время с оптимизацией GForce (по умолчанию). Обратите внимание, что сначала нет setkey. Это то, что известно как холодное или ad hoc, которое является обычной практикой, когда вы хотите группировать по-разному.

> system.time(ans1 <- DT[, lapply(.SD,sum), by=grp])
   user  system elapsed 
 47.520   5.651  53.173 
> system.time(ans1 <- DT[, lapply(.SD,sum), by=grp])
   user  system elapsed 
 47.372   5.676  53.049      # immediate repeat to confirm timing

Теперь отключите оптимизацию GForce (как элемент НОВОСТИ), чтобы увидеть разницу, которую он делает:

> options(datatable.optimize=1)

> system.time(ans2 <- DT[, lapply(.SD,sum), by=grp])
   user  system elapsed 
 97.274   3.383 100.659 
> system.time(ans2 <- DT[, lapply(.SD,sum), by=grp])
   user  system elapsed 
 97.199   3.423 100.624      # immediate repeat to confirm timing

Наконец, подтвердите, что результаты одинаковы:

> identical(ans1,ans2)
[1] TRUE
> print(ans1)
            grp          a          b          c
      1: 695059  16.791281  13.269647 -10.663118
      2: 915263  43.312584 -33.587933   4.490842
      3: 139937   3.967393 -10.386636  -3.766019
      4: 651525  -4.152362   9.339594   7.740136
      5: 438180   4.725874  26.328877   9.063309
     ---                                        
 999996: 372601  -2.087248 -19.936420  21.172860
 999997:  13912  18.414226  -1.744378  -7.951381
 999998: 150074  -4.031619   8.433173 -22.041731
 999999: 385718  11.527876   6.807802   7.405016
1000000: 906246 -13.857315 -23.702011   6.605254

Обратите внимание, что data.table сохраняет порядок групп в соответствии с тем, когда они впервые появились. Чтобы упорядочить сгруппированный результат, используйте keyby= вместо by=.

Чтобы включить оптимизацию GForce (по умолчанию это Inf, чтобы извлечь выгоду из всех оптимизаций):

> options(datatable.optimize=Inf)

Кроме того: если вы не знакомы с синтаксисом lapply(.SD,...), это просто способ применения функции через столбцы по группам. Например, эти две строки эквивалентны:

 DT[, lapply(.SD,sum), by=grp]               # (1)
 DT[, list(sum(a),sum(b),sum(c)), by=grp]    # (2) exactly the same

Первый (1) более полезен, так как у вас больше столбцов, особенно в комбинации с .SDcols для управления подмножеством столбцов для применения функции через.

Элемент NEWS просто пытался сообщить, что не имеет значения, какой из этих синтаксисов используется или передается ли na.rm или нет, оптимизация GForce будет применяться. Он говорит, что вы можете смешивать sum() и mean() в одном вызове (что позволяет синтаксис (2)), но как только вы сделаете что-то еще (например, min()), GForce не будет бить с min еще не сделано; только mean и sum имеют GForce-оптимизации в настоящее время. Вы можете использовать verbose=TRUE, чтобы увидеть, применяется ли GForce.

Подробная информация о машине, используемой для этого времени:

$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                8
On-line CPU(s) list:   0-7
Thread(s) per core:    8
Core(s) per socket:    1
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 62
Stepping:              4
CPU MHz:               2494.022
BogoMIPS:              4988.04
Hypervisor vendor:     Xen
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              25600K
NUMA node0 CPU(s):     0-7