R:循环遍历data.table列(R: loop over columns in data.tab

2019-06-24 10:06发布

我想确定一个大data.table的列类。

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

工作,但显然本地副本保存到内存中:

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

一个循环似乎不可能的,因为一个data.table“与= FALSE”总是导致data.table。

快速和非常脏的方法是:

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

什么是最高贵和有效的方式来做到这一点?

Answer 1:

有简要的调查,它看起来像一个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" 

所以,看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>
> 

注意讨厌unclass在第一行。 ?unclass证实,接受其参数的深层副本。 从这个快看它似乎并不像sapplylapply正在做的拷贝(我不认为他们做了,因为R是擅长写入时复制,而那些不写),而是as.listlapply (其分派给as.list.data.table )。

所以,如果我们避免unclass ,因此应加快。 我们试试吧:

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

所以,是的, 无限美好。

我提出错误报告#2000除去as.list.data.table方法,因为data.table is()已经是一个list ,太。 这可能会加速其实不少成语,如lapply(.SD,...) [编辑:这是固定在V1.8.1]。

谢谢你提出这个问题!



Answer 2:

我看不出有什么错在这样的方法

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

它基本上是你的quick'n'dirty解决方案,但也许有点更清晰(即使没有这么多)...



文章来源: R: loop over columns in data.table