2012-05-14 27 views
8

Voglio determinare le classi di colonne di un grande data.table.R: loop su colonne in data.table

colClasses <- sapply(DT, FUN=function(x)class(x)[1]) 

opere, ma a quanto pare le copie locali sono memorizzati nella memoria:

> memory.size() 
[1] 687.59 
> colClasses <- sapply(DT, class) 
> memory.size() 
[1] 1346.21 

Un ciclo non sembra possibile, perché un data.table "con = FALSE" risultati sempre in un data.table.

un metodo rapido e molto sporco è:

DT1 <- DT[1, ] 
colClasses <- sapply(DT1, FUN=function(x)class(x)[1]) 

Qual è il modo più elegent ed efficiente per fare questo?

+1

Non sono sicuro che la seguo. Perché non solo 'sapply (DT, class)'? –

+0

tempi aggiunti nel testo sopra –

+3

@MatthewDowle: Penso che l'OP significhi che sapply crei variabili temporanee con i sottoinsiemi di data.table per passare a FUN per ogni colonna. Dal momento che data.table è davvero grande e ha un sacco di colonne non è efficiente. Per questo motivo, la sua soluzione è ridurre prima data.table in una riga, quindi chiamare tranquillamente ... – digEmAll

risposta

10

Sono stati analizzati brevemente e sembra un errore data.table.

> DT = data.table(a=1:1e6,b=1:1e6,c=1:1e6,d=1:1e6) 
> Rprofmem() 
> sapply(DT,class) 
     a   b   c   d 
"integer" "integer" "integer" "integer" 
> Rprofmem(NULL) 
> noquote(readLines("Rprofmem.out")) 
[1] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply"  
[2] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply" 
[3] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply" 
[4] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply" 

> tracemem(DT) 
> sapply(DT,class) 
tracemem[000000000431A290 -> 00000000065D70D8]: as.list.data.table as.list lapply sapply 
     a   b   c   d 
"integer" "integer" "integer" "integer" 

Così, guardando as.list.data.table:

> data.table:::as.list.data.table 
function (x, ...) 
{ 
    ans <- unclass(x) 
    setattr(ans, "row.names", NULL) 
    setattr(ans, "sorted", NULL) 
    setattr(ans, ".internal.selfref", NULL) 
    ans 
} 
<environment: namespace:data.table> 
> 

Annotare il fastidioso unclass sulla prima riga. ?unclass conferma che richiede una copia approfondita del suo argomento. Da questo rapido sguardo non sembra che sapply o lapply stiano facendo la copia (non pensavo che lo facessero dato che R è bravo in copy-on-write, e quelli non scrivono), ma piuttosto lo as.list in lapply (che invia a as.list.data.table).

Quindi, se evitiamo il unclass, dovrebbe accelerare. Proviamo:

> DT = data.table(a=1:1e7,b=1:1e7,c=1:1e7,d=1:1e7) 
> system.time(sapply(DT,class)) 
    user system elapsed 
    0.28 0.06 0.35 
> system.time(sapply(DT,class)) # repeat timing a few times and take minimum 
    user system elapsed 
    0.17 0.00 0.17 
> system.time(sapply(DT,class)) 
    user system elapsed 
    0.13 0.04 0.18 
> system.time(sapply(DT,class)) 
    user system elapsed 
    0.14 0.03 0.17 
> assignInNamespace("as.list.data.table",function(x)x,"data.table") 
> data.table:::as.list.data.table 
function(x)x 
> system.time(sapply(DT,class)) 
    user system elapsed 
     0  0  0 
> system.time(sapply(DT,class)) 
    user system elapsed 
    0.01 0.00 0.02 
> system.time(sapply(DT,class)) 
    user system elapsed 
     0  0  0 
> sapply(DT,class) 
     a   b   c   d 
"integer" "integer" "integer" "integer" 
> 

Quindi, sì, infinitamente meglio.

ho sollevato bug report #2000 per rimuovere il metodo as.list.data.table, dal momento che un data.tableis() già un list, anche. Questo potrebbe accelerare un bel po 'di idiomi in realtà, come ad esempio lapply(.SD,...). [EDIT: è stato corretto in v1.8.1].

Grazie per aver chiesto questa domanda !!

+0

Post molto informativo. Grazie per aver mostrato i passaggi che hai usato per eseguire il debug di questo. –

+0

Grazie Matteo! –

2

Non vedo niente di male in un approccio come questo

colClasses <- sapply(head(DT1,1), FUN=class) 

è fondamentalmente la vostra soluzione frettoloso e approssimativo, ma forse un po 'più chiaro (anche se non tanto) ...

+0

È davvero una buona soluzione, ma non elegante come speravo. –

+0

@ user1393348: sì, è ancora una soluzione dopotutto :) – digEmAll