R: перебрать столбцы в 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])

Какой самый эффективный и эффективный способ сделать это?

 Matt Dowle14 мая 2012 г., 16:50
@ digEmAll Ахах, я понял, спасибо.
 Martijn Tennekes14 мая 2012 г., 16:37
поощрения, добавленные в тексте выше
 Matt Dowle14 мая 2012 г., 16:22
Не уверен, что я следую. Почему бы просто неsapply(DT,class)?
 digEmAll14 мая 2012 г., 16:39
@ MatthewDowle: Я думаю, что OP означает, что sapply создает временные переменные с подмножествами data.table для передачи в FUN для каждого столбца. Поскольку его data.table действительно большой и имеет много столбцов, он неэффективен. По этой причине его обходной путь - сначала уменьшить data.table до одной строки, а затем вызвать sapply ...

Ответы на вопрос(2)

Я не вижу ничего плохого в таком подходе

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

это в основном твое быстрое и грязное решение, но, возможно, немного яснее (даже если не очень) ...

 Martijn Tennekes15 мая 2012 г., 09:16
Это действительно хорошее решение, но не такое элегантное, как я надеялся.
 digEmAll15 мая 2012 г., 09:23
@ user1393348: да, это все еще обходной путь :))
Решение Вопроса

Кратко исследовали, и это выглядит как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 подтверждает, что он принимает глубокую копию своего аргумента. На первый взгляд это не похоже наsapply илиlapply делают копирование (я не думаю, что они это сделали, поскольку R хорошо умеет копировать при записи, а те не пишут), а скорееas.list в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 метод, так какdata.table is() ужеlist, слишком. Это может ускорить довольно много идиом, например,lapply(.SD,...). [РЕДАКТИРОВАТЬ: это было исправлено в v1.8.1].

Спасибо, что задали этот вопрос !!

 Josh O'Brien14 мая 2012 г., 20:47
Очень информативный пост. Спасибо за показ шагов, которые вы использовали для отладки.

Ваш ответ на вопрос