2012-05-14 9 views
8

Ich möchte die Spaltenklassen einer großen data.table ermitteln.R: Schleife über Spalten in data.table

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

Werke, aber anscheinend sind lokale Kopien in dem Speicher gespeichert:

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

Eine Schleife nicht möglich zu sein scheint, weil ein data.table "mit = FALSCH" immer in einem data.table führt.

Eine schnelle und sehr schmutzig Methode ist:

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

Was die elegent und effiziente Art und Weise, dies zu tun?

+1

Nicht sicher, ich folge. Warum nicht einfach 'sapply (DT, Klasse)'? –

+0

Timings im obigen Text hinzugefügt –

+3

@MatthewDowle: Ich denke, das OP bedeutet, dass Sapply temporäre Variablen mit den Teilmengen der data.tabelle erstellt, um für jede Spalte zu FUN übergeben. Da seine data.table wirklich groß ist und viele Spalten hat, ist das nicht effizient. Aus diesem Grund ist seine Problemumgehung, die data.table zuerst auf eine Zeile zu reduzieren und dann sapply aufzurufen ... – digEmAll

Antwort

10

Haben kurz untersucht, und es sieht aus wie ein data.table Bug.

> 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" 

Also, suchen Sie in 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> 
> 

Notiere die nervtötende unclass in der ersten Zeile. ?unclass bestätigt, dass es eine tiefe Kopie seines Arguments braucht. Von diesem schnellen Aussehen scheint es nicht oder lapply sind das Kopieren (ich glaube nicht, dass sie getan haben, da R ist gut in Copy-on-Write, und diese sind nicht schriftlich), sondern die as.list in lapply (die an as.list.data.table versendet).

Also, wenn wir die unclass vermeiden, sollte es beschleunigen. Lassen Sie uns versuchen:

> 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" 
> 

Also, ja, unendlich besser.

Ich habe bug report #2000 hob die as.list.data.table Methode, da ein data.tableis() bereits ein list auch zu entfernen. Dies könnte einige Idiome tatsächlich beschleunigen, wie lapply(.SD,...). [BEARBEITEN: Dies wurde in Version 1.8.1 behoben].

Danke für das Stellen dieser Frage !!

+0

Sehr informativer Beitrag. Vielen Dank für die Schritte, die Sie zum Debuggen verwendet haben. –

+0

Danke Matthew! –

2

ich etwas falsch in einem Ansatz nicht

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

wie diese sehen, es ist im Grunde Ihre quick'n'dirty Lösung, aber vielleicht etwas klarer (wenn auch nicht so viel) ...

+0

Es ist in der Tat eine gute Lösung, aber nicht so elegant, wie ich es mir erhofft hatte. –

+0

@ user1393348: Ja, es ist immer noch ein Workaround :) – digEmAll

Verwandte Themen