2012-05-14 24 views
8

Büyük bir data.table sütun sınıflarını belirlemek istiyorum.R: data.table içindeki sütunların üzerinde döngü

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

çalışır, ancak görünüşe göre yerel kopyaları belleğe kaydedilir: "YANLIŞ = ile" bir data.table hep data.table neden olduğu için

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

Bir döngü, mümkün görünmemektedir.

hızlı ve çok kirli bir yöntemdir:

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

bunu yapmanın en elegent ve verimli yolu nedir? Bu

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

o temelde quick'n'dirty çözüm ama belki (hatta değilse bu kadar) biraz daha net gibi bir yaklaşım yanlış bir şey görmüyorum

+1

Takip ettiğimden emin değilim. Neden sadece "sapply (DT, class)" değil? –

+0

zamanlamaları, –

+3

@MatthewDowle üzerindeki metne eklenmiştir: OP'nin, sapply'ın, her bir sütun için FUN'a geçmek için data.table alt kümeleriyle geçici değişkenler oluşturduğu anlamına geldiğini düşünüyorum. Data.table değeri gerçekten büyük olduğundan ve çok fazla sütuna sahip olması verimli değildir. Bu nedenle, onun geçici çözümü data.table bir satır önce azaltmak için, daha sonra sapply çağırmaktır ... – digEmAll

cevap

10

Kısaca araştırdınız ve bir data.table hataya benziyor.

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

Yani, as.list.data.table bakarak:

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

Not ilk satırda sinir bozucu unclass. ?unclass, argümanının derin bir kopyasını aldığını doğrular. Bu hızlı görünümden, sapply veya lapply kopyalarını yapıyor gibi görünmüyor (R-yazma-yazmada iyi olduğu için bunu yapmadıklarını düşünmedim, ve bunlar yazmıyor), ancak lapply içinde as.list (Bu, as.list.data.table'a gönderir).

unclass'dan kurtulursak hızlanmalıdır. deneyelim:

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

Yani, evet, sonsuz daha iyi.

Ben de zaten bir data.tableis() bir list beri as.list.data.table yöntemini kaldırmak bug report #2000 yetiştirdin. Bu, aslında lapply(.SD,...) gibi oldukça az sayıda deyimi hızlandırabilir. [DÜZENLEME: Bu, v1.8.1'de düzeltildi].

Bu soru sorduğunuz için teşekkür ederiz!

+0

Çok bilgilendirici yazı. Bunu hata ayıklamak için kullandığınız adımları gösterdiğiniz için teşekkür ederiz. –

+0

Teşekkürler Matthew! –

2

...

+0

Gerçekten de iyi bir çözüm, ama umduğum kadar şık değil. –

+0

@ user1393348: Evet, hala bir geçici çözüm var :) – digEmAll