2016-03-16 5 views
2

shift в Rdata.table отлично подходит для временных рядов и временных файлов. Но столбцы списков не отстают так же, как и столбцы других элементов. В приведенном ниже коде gearLag руководство/отставание gear правильно, но gearsListLag не отстает gearsList, вместо этого shift работает в пределах gearsList, чтобы пропустить элемент на себе в той же строке.Отложенные списки в data.table R

dt <- data.table(mtcars)[,.(gear, carb, cyl)] 
### Make col of lists 
dt[,carbList:=list(list(unique(carb))), by=.(cyl, gear)] 
### Now I want to lag/lead col of lists 
dt[,.(carb, carbLag=shift(carb) 
    , carbList, carbListLag=shift(carbList, type="lead")), by=cyl] 

    cyl carb carbLag carbList carbListLag 
1: 6 4  NA   4   NA 
2: 6 4  4   4   NA 
3: 6 1  4   1   NA <-- should be 4 here, not NA 
4: 6 1  1   1   NA 
5: 6 4  1   4   NA 
6: 6 4  4   4   NA 
7: 6 6  4   6   NA 
8: 4 1  NA  1,2   2,NA 
9: 4 2  1  1,2   2,NA 
10: 4 2  2  1,2   2,NA 
11: 4 1  2  1,2   2,NA 
12: 4 2  1  1,2   2,NA 
13: 4 1  2  1,2   2,NA 
14: 4 1  1   1   NA <-- should be (1,2) here, not NA 
15: 4 1  1  1,2   2,NA 
16: 4 2  1   2   NA 
17: 4 2  2   2   NA 
18: 4 2  2  1,2   2,NA 
19: 8 2  NA  2,4,3  4, 3,NA 
20: 8 4  2  2,4,3  4, 3,NA 
21: 8 3  4  2,4,3  4, 3,NA 
22: 8 3  3  2,4,3  4, 3,NA 
23: 8 3  3  2,4,3  4, 3,NA 

Любые предложения о том, чтобы отставать от списков так же, как я отстаю от других элементов?

+1

Похоже, что списки не поддерживаются 'shift'. Попробуйте 'shift (список (список (1,2), список (3,4))) # Ошибка Неподдерживаемый тип 'list''. Вы можете узнать из результатов, которые вы видите, что они повторяются по списку и применяют «shift» отдельно к каждому элементу, в соответствии с тем, что происходит при сдвиге (.SD) »(с каждым столбцом, который является элементом списка , сдвинутые отдельно). – Frank

+0

, вы можете указать проблему на странице [github] (https://github.com/Rdatatable/data.table/issues) для более легкого способа справиться с этим. – MichaelChirico

+1

Закрытие этого как дублирующего, так как [лучшее решение было недавно реализован] (https://github.com/Rdatatable/data.table/issues/1595). – Arun

ответ

2

Пользователь Frank отмечает, что shift не поддерживает списки. Вот решение с for и set, которое использует data.table для расчета правильных индексов для отставания внутри группы, но все остальные работают в for. За исключением небольших оптимизаций, это лучший (чистый + быстрый), на который я могу надеяться в пределах data.table?

dt <- data.table(mtcars)[,.(gear, carb, cyl)] 
dt[,carbsList:=list(list(unique(carb))), by=.(cyl, gear)] 
dt[,':='(rowLag=shift(.I), gearLag=shift(gear)), by=cyl] 
dt[,':='(carbsListLag=list())] 
cl_j <- which(names(dt) == "carbsListLag") 
for (i in 1:nrow(dt)) { 
    set(dt, i, cl_j, dt[dt[i,rowLag], list(carbsList)]) 
} 
dt[,.(carb, gear, gearLag, carbsList, carbsListLag, .I, rowLag), by=cyl] 
    cyl carb gear gearLag carbsList carbsListLag I rowLag 
1: 6 4 4  NA   4   NULL 1  NA 
2: 6 4 4  4   4   4 2  1 
3: 6 1 3  4   1   4 4  2 
4: 6 1 3  3   1   1 6  4 
... 
13: 4 1 4  4  1,2   1,2 20  19 
14: 4 1 3  4   1   1,2 21  20 
15: 4 1 4  3  1,2   1 26  21 
16: 4 2 5  4   2   1,2 27  26 
17: 4 2 5  5   2   2 28  27 
18: 4 2 4  5  1,2   2 32  28 
19: 8 2 3  NA  2,4,3   NULL 5  NA 
20: 8 4 3  3  2,4,3  2,4,3 7  5 
+0

Третий аргумент 'set' может быть именем столбца, например,« carbsListLag »вместо числа,' 'c1_j'. Кроме того, я думаю, ваш ': =' может быть в один шаг вместо двух ..? Наконец, может потребоваться 'NA' вместо' NULL' (я не уверен). – Frank

4

Это задокументированное поведение. Вот часть примера на ?shift:

# on lists 
ll = list(1:3, letters[4:1], runif(2)) 
shift(ll, 1, type="lead") 
# [[1]] 
# [1] 2 3 NA 
# 
# [[2]] 
# [1] "c" "b" "a" NA 
# 
# [[3]] 
# [1] 0.1190792  NA 

Чтобы обойти эту проблему, вы можете сделать уникальный идентификатор для каждого значения списка:

dt[, carbList_id := match(carbList, unique(carbList))] 

carbList_map = dt[, .(carbList = list(carbList[[1]])), by=carbList_id] 

# carbList_id carbList 
# 1:   1  4 
# 2:   2  1,2 
# 3:   3  1 
# 4:   4 2,4,3 
# 5:   5  2 
# 6:   6  4,8 
# 7:   7  6 

# or stick with long-form: 
carbList_map = dt[, .(carb = carbList[[1]]), by=carbList_id] 

#  carbList_id carb 
# 1:   1 4 
# 2:   2 1 
# 3:   2 2 
# 4:   3 1 
# 5:   4 2 
# 6:   4 4 
# 7:   4 3 
# 8:   5 2 
# 9:   6 4 
# 10:   6 8 
# 11:   7 6 

Затем, shift или что-то еще с новой колонкой ID. Когда вам снова понадобится значение carbList, вам придется объединиться с новой таблицей.

В качестве альтернативы, если вам действительно не нужно работать со значениями, а просто для их просмотра, подумайте о том, чтобы вместо этого создать строку, например, carbList:=toString(sort(unique(carb))) или с paste0.

Сторона примечания: сортировать перед использованием toString, paste0 или list.