Извлечение столбцов из таблицы больших данных в небольшие таблицы данных и сохранение в списке

#r #list #data.table #extract

#r #Список #data.table #извлечение

Вопрос:

Я получаю таблицу данных (временные ряды для разных продуктов в зависимости от дат) с внешнего сервера, которая может иметь следующее максимальное количество столбцов (дата всегда является первым столбцом, а все остальные столбцы могут существовать или нет, или есть только два дополнительных столбца или что-то еще):

 set.seed(123)
dt.data <- data.table(date = seq(as.Date('2020-01-01'), by = '1 day', length.out = 365),
                      'DEB Cal-2019' = rnorm(365, 2, 1), 'DEB Cal-2021' = rnorm(365, 2, 1),
                      'DEB Cal-2022' = rnorm(365, 2, 1), 'DEB Cal-2023' = rnorm(365, 2, 1),
                      'ATB Cal-2019' = rnorm(365, 2, 1), 'ATB Cal-2021' = rnorm(365, 2, 1),
                      'ATB Cal-2022' = rnorm(365, 2, 1), 'ATB Cal-2023' = rnorm(365, 2, 1),
                      'TTF Cal-2019' = rnorm(365, 2, 1), 'TTF Cal-2021' = rnorm(365, 2, 1),
                      'TTF Cal-2022' = rnorm(365, 2, 1), 'TTF Cal-2023' = rnorm(365, 2, 1),
                      'NCG Cal-2019' = rnorm(365, 2, 1), 'NCG Cal-2021' = rnorm(365, 2, 1),
                      'NCG Cal-2022' = rnorm(365, 2, 1), 'NCG Cal-2023' = rnorm(365, 2, 1),
                      'AUTVTP Cal-2019' = rnorm(365, 2, 1), 'AUTVTP Cal-2021' = rnorm(365, 2, 1),
                      'AUTVTP Cal-2022' = rnorm(365, 2, 1), 'AUTVTP Cal-2023' = rnorm(365, 2, 1),
                      'ATW Cal-2019' = rnorm(365, 2, 1), 'ATW Cal-2021' = rnorm(365, 2, 1),
                      'ATW Cal-2022' = rnorm(365, 2, 1), 'ATW Cal-2023' = rnorm(365, 2, 1),
                      'BRN Cal-2019' = rnorm(365, 2, 1), 'BRN Cal-2021' = rnorm(365, 2, 1),
                      'BRN Cal-2022' = rnorm(365, 2, 1), 'BRN Cal-2023' = rnorm(365, 2, 1),
                      'FEUA MDEC1' = rnorm(365, 2, 1),
                      check.names = FALSE)
  

Теперь я хотел бы сохранить / извлечь каждый встречающийся столбец со столбцом даты в его собственной таблице данных. В идеале все извлеченные таблицы данных затем добавляются в список. Я знаю, что я должен как-то сделать это с помощью цикла for, но я не могу его решить.

После того, как я получил отдельные таблицы данных для каждого продукта, мне нужно было бы сделать следующее для каждой из таблиц данных (пример таблицы данных теперь используется здесь для AUTVTP Cal-2022 ):

 DT <- data.table(date = seq(as.Date('2020-01-01'), by = '1 day', length.out = 365),
                 'AUTVTP Cal-2022' = rnorm(365, 2, 1), check.names = FALSE)


DT <- DT %>%
  mutate(month = format(date, '%b'), 
         date = format(date, '%d')) %>%
  tidyr::pivot_wider(names_from = date, values_from = 'AUTVTP Cal-2022') %>%
  relocate(`01`, .after = month)

## Calculate monthly and quarterly mean values: ##
DT <- setDT(DT)[, monthAvg := rowMeans(.SD, na.rm = TRUE), .SDcols = -1]
DT <- DT[, quartAvg := mean(monthAvg), ceiling(seq_len(nrow(DT))/3)]
DT <- DT[, yearAvg := mean(monthAvg), ceiling(seq_len(nrow(DT))/12)]

## Round all values of the data table to 2 digits: ##
DT <- DT %>% mutate_if(is.numeric, round, 2)
  

КАК Я МОГУ ЭТО СДЕЛАТЬ?

Ответ №1:

Преобразовать в длинный формат, затем разделить.

 split(
  melt(dt.data, id.vars = "date"),
  by = "variable", keep.by = FALSE)
  

Затем вы можете использовать lapply для итерации по списку и делать все, что делает ваш код tidyverse.

Однако, как правило, вы не должны разделять data.table. Это неэффективно и часто не требуется.

Редактировать:

Я предлагаю вам забыть о разделении. Оберните свой код в функцию, подобную этой:

 foo <- function(DT, colname) {
  DT <- DT[, c("date", colname), with = FALSE]
  DT <- DT %>%
    mutate(month = format(date, '%b'), 
           date = format(date, '%d')) %>%
    tidyr::pivot_wider(names_from = date, values_from = colname) %>%
    relocate(`01`, .after = month)
  
  ## Calculate monthly and quarterly mean values: ##
  DT <- setDT(DT)[, monthAvg := rowMeans(.SD, na.rm = TRUE), .SDcols = -1]
  DT <- DT[, quartAvg := mean(monthAvg), ceiling(seq_len(nrow(DT))/3)]
  DT <- DT[, yearAvg := mean(monthAvg), ceiling(seq_len(nrow(DT))/12)]
  
  ## Round all values of the data table to 2 digits: ##
  DT %>% mutate_if(is.numeric, round, 2)
}
  

Затем, когда вам понадобится таблица для определенного столбца в вашем блестящем приложении, вы можете просто вызвать эту функцию:

 foo(dt.data, 'DEB Cal-2019')
  

Если вы настаиваете на предварительном вычислении списка:

 lapply(names(dt.data)[names(dt.data) != "date"], 
       foo, DT = dt.data)
  

Комментарии:

1. Когда я использую последнюю часть кода, где я вычисляю ежемесячные, квартальные и годовые средние для каждой таблицы данных списка?

2. Вы делаете это перед разделением. Вы можете использовать lapply внутри data.table для перебора столбцов.

3. Я не совсем знаком с apply соглашением? Поскольку мне нужно рассчитать ежемесячные, квартальные и годовые средние значения для каждой небольшой таблицы данных, как я могу это сделать перед разделением?

4. Ваш пример кода мне бесполезен, потому что он написан на tidyverse. Я пользователь старой школы R, который этим не пользуется. Ваше объяснение очень неясно. Вы не должны начинать с разделения data.table. Если вам нужно, вы можете закончить с этим. Я все еще не понял, какова ваша фактическая цель. И, пожалуйста, не объясняйте шаги, которые, по вашему мнению , вам нужны.

5. См help("setNames") . .

Ответ №2:

Создайте список фреймов данных, используя и первый столбец для каждого списка. split.default cbind

 lapply(split.default(dt.data[, -1], names(dt.data[, -1])), cbind, dt.data[, 1])
  

Комментарии:

1. Спасибо за ваш ответ. Но тогда мне все равно придется применять вторую часть кода сверху к каждой отдельной таблице данных в списке (ежемесячное, квартальное, годовое среднее значение для каждой таблицы данных и всех таблиц данных, преобразуемых в широкий формат).

2. Из названия и описания вашего вопроса я понимаю, что вы хотите разделить data.table на два столбца списка таблиц данных, которые дает мой ответ. Если вы пишете функцию, которую хотите применить к каждому отдельному списку, вы можете применить функцию, используя lapply i.e lapply(result_from_above, fun) .