Split data.table
У меня есть таблица данных, которую я хочу разбить на две части. Я делаю это следующим образом:
dt <- data.table(a=c(1,2,3,3),b=c(1,1,2,2))
sdt <- split(dt,dt$b==2)
но если я хочу сделать что-то вроде этого следующим шагом
sdt[[1]][,c:=.N,by=a]
Появляется следующее предупреждающее сообщение.
Предупреждающее сообщение: В [.data.table
(sdt [[1]], :=
(c,.N), by = a): Недопустимый .internal.selfref обнаружен и исправлен, взяв копию целую таблицу, так что: = может добавить этот новый столбец по ссылке. Загар более ранняя точка, эта таблица данных была скопирована R. Избегайте ключа < -, имена < - и attr < - которые в R в настоящее время (и странно) могут копировать все Таблица данных. Вместо этого используйте синтаксис set *, чтобы избежать копирования: setkey(), setnames() и setattr(). Кроме того, список (DT1, DT2) скопирует весь DT1 и DT2 (R list() копирует именованные объекты), вместо этого используйте reflist(), если необходимо (должно быть реализовано). Если это сообщение не помогает, пожалуйста, сообщите о datatable-help, чтобы устранить основную причину.
Просто интересно, есть ли лучший способ разбить таблицу так, чтобы она была более эффективной (и не получила бы это сообщение)?
Ответы
Ответ 1
Это работает в v1.8.7 (и может работать и в версии 1.8.6):
> sdt = lapply(split(1:nrow(dt), dt$b==2), function(x)dt[x])
> sdt
$`FALSE`
a b
1: 1 1
2: 2 1
$`TRUE`
a b
1: 3 2
2: 3 2
> sdt[[1]][,c:=.N,by=a] # now no warning
> sdt
$`FALSE`
a b c
1: 1 1 1
2: 2 1 1
$`TRUE`
a b
1: 3 2
2: 3 2
Но, как сказал @mnel, это неэффективно. Пожалуйста, избегайте расщепления, если это возможно.
Ответ 2
Я искал способ сделать раскол в data.table, я столкнулся с этим старым вопросом.
Когда-то раскол - это то, что вы хотите сделать, а метод data.table "by" не удобен.
На самом деле вы можете легко сделать свой раскол вручную с помощью data.table только инструкций и работает очень эффективно:
SplitDataTable <- function(dt,attr) {
boundaries=c(0,which(head(dt[[attr]],-1)!=tail(dt[[attr]],-1)),nrow(dt))
return(
mapply(
function(start,end) {dt[start:end,]},
head(boundaries,-1)+1,
tail(boundaries,-1),
SIMPLIFY=F))
}
Ответ 3
Как упоминалось выше (@jangorecki), пакет data.table
уже имеет свою собственную функцию для разбиения. В этом упрощенном случае мы можем использовать:
> dt <- data.table(a = c(1, 2, 3, 3), b = c(1, 1, 2, 2))
> split(dt, by = "b")
$'1'
a b
1: 1 1
2: 2 1
$'2'
a b
1: 3 2
2: 3 2
Для более сложных/конкретных случаев я бы порекомендовал создать новую переменную в data.table, используя функции по ссылке :=
или set
, а затем вызвать функцию split
. Если вы заботитесь о производительности, всегда оставайтесь в среде data.table, например, dt[, SplitCriteria := (...)]
, а не вычисляйте переменную разделения извне.