2015-04-16 10 views
13

Czasami muszę policzyć liczbę elementów innych niż NA w jednej lub drugiej kolumnie w moim data.table. Jaki jest najlepszy sposób na zrobienie tego?Efektywne liczenie elementów innych niż NA w data.table

Dla konkretności, niech pracują z tym:

DT <- data.table(id = sample(100, size = 1e6, replace = TRUE), 
       var = sample(c(1, 0, NA), size = 1e6, replace = TRUE), key = "id") 

Pierwszą rzeczą, która przychodzi mi do głowy, działa tak:

DT[!is.na(var), N := .N, by = id] 

Ale to ma niestety wadę, że N nie zostanie przypisany do dowolnego wiersza, w którym brakuje var, tj. DT[is.na(var), N] = NA.

Więc to obejść poprzez dołączenie:

DT[!is.na(var), N:= .N, by = id][ , N := max(N, na.rm = TRUE), by = id] #OPTION 1 

Jednak nie jestem pewien, że to jest najlepsze podejście; Inną opcją myślałem i jeden z sugestią analogowej na this pytanie do data.frame s byłoby:

DT[ , N := length(var[!is.na(var)]), by = id] # OPTION 2 

i

DT[ , N := sum(!is.na(var)), by = id] # OPTION 3 

Porównując czas obliczeń z nich (średnio ponad 100 prób), ostatni wydaje aby być najszybszym:

OPTION 1 | OPTION 2 | OPTION 3 
    .075 | .065 | .043 

Czy ktoś wie szybszą drogę do data.table?

Odpowiedz

7

Tak, opcja 3 wydaje się najlepsza. Dodałem kolejną, która jest ważna tylko wtedy, gdy rozważasz zmianę klucza danych.tabeli z id na var, ale wciąż opcja 3 jest najszybsza na twoich danych.

library(microbenchmark) 
library(data.table) 

dt<-data.table(id=(1:100)[sample(10,size=1e6,replace=T)],var=c(1,0,NA)[sample(3,size=1e6,replace=T)],key=c("var")) 

dt1 <- copy(dt) 
dt2 <- copy(dt) 
dt3 <- copy(dt) 
dt4 <- copy(dt) 

microbenchmark(times=10L, 
       dt1[!is.na(var),.N,by=id][,max(N,na.rm=T),by=id], 
       dt2[,length(var[!is.na(var)]),by=id], 
       dt3[,sum(!is.na(var)),by=id], 
       dt4[.(c(1,0)),.N,id,nomatch=0L]) 
# Unit: milliseconds 
#               expr  min  lq  mean median  uq  max neval 
# dt1[!is.na(var), .N, by = id][, max(N, na.rm = T), by = id] 95.14981 95.79291 105.18515 100.16742 112.02088 131.87403 10 
#      dt2[, length(var[!is.na(var)]), by = id] 83.17203 85.91365 88.54663 86.93693 89.56223 100.57788 10 
#        dt3[, sum(!is.na(var)), by = id] 45.99405 47.81774 50.65637 49.60966 51.77160 61.92701 10 
#      dt4[.(c(1, 0)), .N, id, nomatch = 0L] 78.50544 80.95087 89.09415 89.47084 96.22914 100.55434 10 
+2

@MichaelChirico, spojrzeć w [Klawisze i binarnych podzbiorów wyszukiwania opartych] (https://github.com/Rdatatable/data.table/wiki/Getting-started) (i niech nas wie, jeśli znajdziesz coś niejasnego/do dodania [tutaj] (https://github.com/Rdatatable/data.table/issues/944). – Arun

+0

Istnieje jeszcze jedna opcja: 'dt5 [,. N [! is. na (var)], by = id] '- trzeci najszybszy w moim systemie i znacznie lepszy niż opcje 1 i 2. Z jakiegoś powodu opcja 3 daje odpowiedzi binarne (0,1) zamiast zliczeń, jeśli więcej niż jeden" przez Używana jest zmienna. Sugerowana opcja 5 daje prawidłowe wartości. –

Powiązane problemy