10

我想确定大型 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 "with=FALSE" 总是导致 data.table。

一种快速且非常肮脏的方法是:

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

什么是最优雅和最有效的方法?

4

2 回答 2

11

简单调查了一下,好像是个data.tablebug。

> 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.listin lapply(它发送到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方法,因为 adata.table is()已经 alist了。这实际上可能会加速很多成语,例如lapply(.SD,...). [编辑:这已在 v1.8.1 中修复]。

谢谢你问这个问题!!

于 2012-05-14T18:07:33.873 回答
2

我认为这样的方法没有任何问题

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

它基本上是您的快速'n'dirty解决方案,但可能更清晰(即使不是那么多)......

于 2012-05-14T14:55:01.987 回答