Преобразование длинной таблицы данных в список широких таблиц данных

Мой вопрос - это расширение поставленного здесь вопроса Как преобразовать данные из длинного в широкоформатный, так что я сформулирую это аналогичным образом.

Разница в том, что я хочу переставить одну длинную таблицу данных в list с широкими таблицами данных.

dat <- data.table(
    sim = rep(c(1,2), each=4),
    time = rep(1:4, 2),
    value1 = rnorm(8),
    value2 = rnorm(8)
    )

dat
   sim  time      value1  value2
1    1     1      0.3407  0.5167
2    1     2     -0.7033  0.8416
3    1     3     -0.3795 -0.4717
4    1     4     -0.7460  0.8479
5    2     1      0.8981 -0.7163
6    2     2     -0.3347 -0.6849
7    2     3      0.5013  0.8941
8    2     4     -0.1745  0.0795

Я хочу изменить его форму так, чтобы у меня был list с широкими таблицами данных с именами value1, value2 ... value99 и т. д.

l = list()


l[["value1"]]

    sim        1       2       3       4
1     1   0.3407 -0.7033 -0.3795 -0.7460
5     2  -0.8981 -0.3347 -0.5013 -0.1745

l[["value2"]]

    sim        1       2       3       4
1     1   0.5167  0.8416 -0.4717  0.8479
5     2  -0.7163 -0.6849  0.8941  0.0795

Тег Таблица данных немного неоднозначен; вы намереваетесь использовать Таблица данных (пакет R's data.table)? Если нет, то этот тег не подходит для этого вопроса, возможно, предпочтительнее data.frame для кадров R.

r2evans 07.04.2021 17:01

Да, я использую пакет data.table. У меня по ошибке был dataframe в коде, спасибо

orange90 07.04.2021 17:15

(Вы можете увидеть множество ответов на основе dplyr, которые имеют большое значение :-)

r2evans 07.04.2021 17:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
51
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Моим решением этой проблемы было бы создание вложенного массива данных результатов. Я дал краткое описание метода, за которым следует репрезент.

Я бы сделал это, используя pivot_wider() и pivot_longer() для изменения формы данных. pivot_longer используется первым, чтобы каждая строка содержала только 1 значение с меткой для времени, моделирования и того, является ли это значением одно или два. Затем, используя pivot_wider, каждая строка будет содержать значения в каждый момент времени с меткой для моделирования и набором значений, которые они представляют. (значение1 или значение2).

Наконец, мы вкладываем фрейм данных с помощью nest, который хранит все данные для каждого набора значений в фрейме данных. При необходимости nested_vals$data может получить доступ к нему как к массиву фреймов данных, где nested_val - это объект, которому мы назначили вложенный фрейм данных.

library(tidyverse)

#Setup data
dat <- data.frame(
  sim = rep(c(1,2), each=4),
  time = rep(1:4, 2),
  value1 = rnorm(8),
  value2 = rnorm(8)
)

# Construct nested dataframe
nested_vals <- dat %>%
  # Format dataset in tidy format
  pivot_longer(cols = c(value1, value2)) %>% 
  # Move the name of the data to the beginning of the dataframe
  relocate(name) %>% 
  # Pivot to matrix form as requested (i.e. times as columns, sims as rows)
  pivot_wider(id_cols = c(name, sim), names_from = time, values_from = value) %>% 
  # Nest results by name
  nest(-name)
#> Warning: All elements of `...` must be named.
#> Did you want `data = c(sim, `1`, `2`, `3`, `4`)`?

nested_vals
#> # A tibble: 2 x 2
#>   name   data                
#>   <chr>  <list>              
#> 1 value1 <tibble[,5] [2 x 5]>
#> 2 value2 <tibble[,5] [2 x 5]>

nested_vals$data[[2]]
#> # A tibble: 2 x 5
#>     sim     `1`      `2`    `3`    `4`
#>   <dbl>   <dbl>    <dbl>  <dbl>  <dbl>
#> 1     1  0.0639 0.250    -1.28   0.850
#> 2     2 -1.90   0.000421  0.704 -0.164

Created on 2021-04-07 by the reprex package (v2.0.0)

Решение tidyverse может быть:

library(dplyr)
library(purrr)
library(tidyr)

dat_longer <- dat %>%
  tidyr::pivot_longer(starts_with("value"), names_to = "col_name", values_to = "values")

list_wide <- purrr::map(unique(dat_longer[["col_name"]]),
                         ~dat_longer %>%
                           dplyr::filter(col_name==.x) %>%
                           tidyr::pivot_wider(values_from = "values", names_from = "time") %>% 
                           select(-col_name)) %>% 
  purrr::set_names(unique(dat_longer[["col_name"]]))

$value1
# A tibble: 2 x 5
    sim    `1`    `2`    `3`    `4`
  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1     1 -0.710 -0.334 -0.370  0.777
2     2  0.130  0.877  1.24  -0.202

$value2
# A tibble: 2 x 5
    sim    `1`    `2`    `3`    `4`
  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1     1 -0.719 -0.909 0.0821 -0.158
2     2 -0.706  1.51  0.234   1.09 
Ответ принят как подходящий

Два варианта.

Таблица данных

library(data.table)
tmp <- dcast(melt(as.data.table(dat), id = c("sim", "time")), sim + variable ~ time)
tmp <- split(tmp, tmp$variable)
tmp <- lapply(tmp, set, i = NULL, j = "variable", value = NULL)
tmp
# $value1
#      sim             1          2          3          4
#    <num>         <num>      <num>      <num>      <num>
# 1:     1  1.0458737762 -0.4845954  0.1891288 0.05100633
# 2:     2 -0.0002406689  1.8093820 -0.8253280 1.14547045
# $value2
#      sim           1          2           3         4
#    <num>       <num>      <num>       <num>     <num>
# 1:     1  0.03157319 -0.8352058 -0.06876365 0.7467717
# 2:     2 -0.42551873 -0.7720822  0.15276411 0.9885968

Я часто использую magrittr::%>% с data.table, так что его можно преобразовать в

library(data.table)
library(magrittr) # if %>% is not already available
as.data.table(dat) %>%
  melt(., id = c("sim", "time")) %>%
  dcast(., sim + variable ~ time) %>%
  split(., .$variable) %>%
  lapply(., set, i = NULL, j = "variable", value = NULL)
# $value1
#      sim             1          2          3          4
#    <num>         <num>      <num>      <num>      <num>
# 1:     1  1.0458737762 -0.4845954  0.1891288 0.05100633
# 2:     2 -0.0002406689  1.8093820 -0.8253280 1.14547045
# $value2
#      sim           1          2           3         4
#    <num>       <num>      <num>       <num>     <num>
# 1:     1  0.03157319 -0.8352058 -0.06876365 0.7467717
# 2:     2 -0.42551873 -0.7720822  0.15276411 0.9885968

тидиверс

library(dplyr)
library(tidyr) # pivot_longer, pivot_wider
dat %>%
  pivot_longer(., -c(sim, time)) %>%
  pivot_wider(., names_from = time, values_from = value) %>%
  split(., .$name) %>%
  lapply(., select, -name)
# $value1
# # A tibble: 2 x 5
#     sim       `1`    `2`    `3`    `4`
#   <dbl>     <dbl>  <dbl>  <dbl>  <dbl>
# 1     1  1.05     -0.485  0.189 0.0510
# 2     2 -0.000241  1.81  -0.825 1.15  
# $value2
# # A tibble: 2 x 5
#     sim     `1`    `2`     `3`   `4`
#   <dbl>   <dbl>  <dbl>   <dbl> <dbl>
# 1     1  0.0316 -0.835 -0.0688 0.747
# 2     2 -0.426  -0.772  0.153  0.989

Я никогда не думаю о dcast! Очень аккуратное решение

orange90 07.04.2021 18:33

Две вещи: уловка здесь в том, чтобы изменить форму дважды (длиннее, затем шире); и dcast / melt аналогичны pivot_longer / pivot_wider от известного tidyr. Рад, что это сработало для вас.

r2evans 07.04.2021 18:34

Еще один способ с однотрубным синтаксисом

library(tidyverse)
dat %>% pivot_longer(c(value1, value2)) %>%
  group_split(name) %>% setNames(map(., ~.x[[3]][1])) %>%
  map(~ .x %>% pivot_wider(id_cols = sim, names_from = time, values_from = value))

$value1
# A tibble: 2 x 5
    sim    `1`     `2`    `3`    `4`
  <dbl>  <dbl>   <dbl>  <dbl>  <dbl>
1     1 -0.851 -0.0484 -0.656 -0.121
2     2 -0.645  1.59   -0.274  0.445

$value2
# A tibble: 2 x 5
    sim   `1`    `2`    `3`   `4`
  <dbl> <dbl>  <dbl>  <dbl> <dbl>
1     1  1.46 -1.62  -0.672 1.43 
2     2  1.65  0.790  0.495 0.162

Другой подход:

library(dplyr)
library(tidyr)
wide_dat <- dat %>% pivot_wider(id_cols = sim, names_from = time, values_from = starts_with('value'))
lapply(lapply(split.default(wide_dat[-1], sub('_\\d','',names(wide_dat[-1]))), function(x) cbind(wide_dat[1],x)), setNames, c('sim', 1:4))
$value1
  sim          1         2        3         4
1   1 -0.1704969 0.2820143 1.181898 2.2377396
2   2  2.1920534 0.8214070 0.421177 0.7601796

$value2
  sim          1         2          3          4
1   1  0.1760887 0.3440053 -0.8435849  0.6729751
2   2 -0.1714095 1.5125986 -0.5739871 -0.9648294

Другие вопросы по теме