О GForce в data.table 1.9.2

Я не знаю, как извлечь большую выгоду из GForce в data.table 1.9.2

Новая оптимизация: GForce. Вместо того, чтобы группировать данные, местоположения групп передаются в сгруппированные версии суммы и среднего (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?

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


person Bigchao    schedule 03.03.2014    source источник


Ответы (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 первого. Это то, что известно как cold by или ad hoc by, что является обычной практикой, когда вы хотите группировать разными способами.

> 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 (согласно статье NEWS), чтобы увидеть разницу:

> 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
person Matt Dowle    schedule 03.03.2014