R: цикл по столбцам в данных.таблица
Я хочу определить классы столбцов больших данных.таблица.
colClasses <- sapply(DT, FUN=function(x)class(x)[1])
работает, но, по-видимому, локальные копии хранятся в памяти:
> memory.size()
[1] 687.59
> colClasses <- sapply(DT, class)
> memory.size()
[1] 1346.21
цикл кажется невозможным, потому что данные.таблица "with=FALSE" всегда приводит к данным.таблица.
быстрый и очень грязный метод:
DT1 <- DT[1, ]
colClasses <- sapply(DT1, FUN=function(x)class(x)[1])
какой самый элегантный и эффективный способ сделать это?
2 ответов
кратко исследовали, и это похоже на 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,...)
. [EDIT: это было исправлено в v1.8.1].
Спасибо, что задали этот вопрос!!
Я не вижу ничего плохого в таком подходе
colClasses <- sapply(head(DT1,1), FUN=class)
это в основном ваше быстрое решение, но, возможно, немного яснее (даже если не так много)...