Вопрос по r – R: перебрать столбцы в data.table

8

Я хочу определить классы столбцов большой таблицы данных.

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

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

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

Ваш Ответ

2   ответа
10

Кратко исследовали, и это выглядит как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'Brien
2

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

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

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

Это действительно хорошее решение, но не такое элегантное, как я надеялся. Martijn Tennekes
@ user1393348: да, это все еще обходной путь :)) digEmAll

Похожие вопросы