привязка списка списка data.table - PullRequest
2 голосов
/ 26 октября 2019

Звучит глупо, но у меня есть список из списка data.table, например:

list(list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)),
     list(table1=data.table(A1=-1:3, B1=-2:2),
          table2=data.table(A2=-3:1, B2=-4:0)),
     list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)))

Я бы хотел rbind каждый tableX вместе и вернуть список data.tableт. е.

list(table1=data.table(A1=c(1:3, -1:3, 1:3), B1=c(2:4, -2:2, 2:4)),
     table2=data.table(A2=c(3:1, -3:1, 3:1), B2=c(4:2, -4:0, 4:2)))

В сценарии реального мира входными данными будет список из тысяч списков из десятков data.table с сотнями столбцов в каждом, поэтому жесткое кодирование не будет возможным.

Ответы [ 5 ]

2 голосов
/ 26 октября 2019

В качестве варианта можно было бы сначала указать purrr::transpose ваш список, а затем использовать rbindlist и Map

out <- Map(data.table::rbindlist, purrr::transpose(l))

Проверить выходные данные

identical(out,
          list(table1=data.table(A1=c(1:3, -1:3, 1:3), B1=c(2:4, -2:2, 2:4)),
               table2=data.table(A2=c(3:1, -3:1, 3:1), B2=c(4:2, -4:0, 4:2))))
#[1] TRUE

data

l <- list(list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)),
     list(table1=data.table(A1=-1:3, B1=-2:2),
          table2=data.table(A2=-3:1, B2=-4:0)),
     list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)))
2 голосов
/ 26 октября 2019

Рассмотрим базовое решение семейства R с функцией извлечения, [[:

table_names <- unlist(unique(lapply(my_original_list, names)))

final_list <- sapply(table_names, function(t) 
                       rbindlist(lapply(my_original_list, `[[`, t)),
                     simplify=FALSE)

final_list
1 голос
/ 26 октября 2019

Вот базовое решение (с и rbindlist)

library(data.table)

apply(simplify2array(lst), 1, rbindlist)

Результат такой же, как и предполагалось:

identical(list(table1=data.table(A1=c(1:3, -1:3, 1:3), B1=c(2:4, -2:2, 2:4)),
              table2=data.table(A2=c(3:1, -3:1, 3:1), B2=c(4:2, -4:0, 4:2))),
          apply(simplify2array(lst), 1, rbindlist))

# [1] TRUE
1 голос
/ 26 октября 2019

Возможно, это не самое элегантное или эффективное решение, но я предлагаю сначала создать список из tableX s для данного числа X. Затем сделайте rbind в этом списке и поместите вывод в новый список, проиндексированный должным образом. Возможно, вам придется изменить в зависимости от особенностей ваших фактических данных - я предполагаю, что каждый список в вашем списке имеет все tableX, и что они упорядочены.

См. Ниже:

library(data.table)
library(testthat)

dt.list <- list(list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)),
     list(table1=data.table(A1=-1:3, B1=-2:2),
          table2=data.table(A2=-3:1, B2=-4:0)),
     list(table1=data.table(A1=1:3, B1=2:4),
          table2=data.table(A2=3:1, B2=4:2)))

dt.output <- 
  list(table1=data.table(A1=c(1:3, -1:3, 1:3), B1=c(2:4, -2:2, 2:4)),
     table2=data.table(A2=c(3:1, -3:1, 3:1), B2=c(4:2, -4:0, 4:2)))


# Extract number of tableX's -- assuming same number in each list element.
mylist <- vector(mode = "list", length = length(dt.list[[1]]))
for (li in seq(length(mylist))) {
  # Extract tableXs, put into list.
  list.tableX <- lapply(dt.list, function(x) {
                    return(x[[li]])
                  })
  # Use rbind to put together
  mylist[[li]] <- do.call("rbind", list.tableX)
  names(mylist)[li] <- paste0("table", li)
}

testthat::expect_identical(dt.output, mylist)
0 голосов
/ 26 октября 2019

Моей первой мыслью было сначала transpose, но перенос может быть вычислительно дорогим. Можно кратко использовать нормальное индексирование с помощью purrr::map_dfr:

library(purrr)
map(1:2, ~ map_dfr(l, .))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...