Переформатирование кадра данных в широкий формат в R

Мне было интересно, есть ли способ переформатировать мой DATA в мой Desired_output ниже?

Конкретно для каждого уникального study мы склеиваем пару pre и postNUMBER вместе, отдельно для t и c.

Например, для study == 2 мы склеиваем пару pre и postNUMBER вместе, идя ОТ:

study time   nt nc    mt    mc  sdt  sdc  outcome
2     pre    38 48  1.89  2.22 0.40 0.76  fram
2     post1  38 48  4.07  2.52 2.20 1.58  fram

К:

study time            group  n    mpre     mpost  sdpre  sdpost outcome
2     pre-post1       t      38   1.89     4.07   0.40   2.20   fram
2     pre-post1       c      48   2.22     2.52   0.76   1.58   fram

пс. Если уникальный study в DATA не содержал pre (состоял только из postNUMBER) или postNUMBER (состоял только из pre), мы просто его опускаем.

DATA <- read.table(header=T, text = "
study time   nt nc    mt    mc  sdt  sdc  outcome
1     pre    28 58  0.89  1.22 1.40 1.76  Conv
1     post1  28 58  5.07  3.52 3.20 2.58  Conv
1     post2  28 58  3.64  2.86 3.15 2.80  Conv
2     pre    38 48  1.89  2.22 0.40 0.76  fram
2     post1  38 48  4.07  2.52 2.20 1.58  fram
3     post1  31 18  2.07  1.52 1.20 0.58  voca
3     post2  32 18  3.07  2.32 1.12 9.85  voca
")

Desired_output <- read.table(header=T, text = "
study time            group  n    mpre     mpost  sdpre  sdpost outcome
1     pre-post1       t      28   0.89     5.07   1.40   3.20   Conv
1     pre-post2       t      28   0.89     3.64   1.40   3.15   Conv
1     pre-post1       c      58   1.22     3.52   1.76   2.58   Conv
1     pre-post2       c      58   1.22     2.86   1.76   2.80   Conv
2     pre-post1       t      38   1.89     4.07   0.40   2.20   fram
2     pre-post1       c      48   2.22     2.52   0.76   1.58   fram
")
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
62
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

tidyverse Предлагается pivot_longer() в первый раз иметь по одной строке на каждую учебную группу (и столбец для n, m и sd). Во второй раз вы можете left_join строки «опубликовать» (filter(time! = "pre") с «предварительными» строками (filter(time= = "pre"); с соответствующим аргументом.

У меня select несколько колонок. Обратите внимание, что я сохранил строку без pre с некоторыми NA ; их можно отфильтровать, если вы хотите их исключить.

library(tidyverse)

DATA <- read.table(header=T, text = "
study time   nt nc    mt    mc  sdt  sdc  outcome
1     pre    28 58  0.89  1.22 1.40 1.76  Conv
1     post1  28 58  5.07  3.52 3.20 2.58  Conv
1     post2  28 58  3.64  2.86 3.15 2.80  Conv
2     pre    38 48  1.89  2.22 0.40 0.76  fram
2     post1  38 48  4.07  2.52 2.20 1.58  fram
3     post1  31 18  2.07  1.52 1.20 0.58  voca
3     post2  32 18  3.07  2.32 1.12 9.85  voca
")

data2 = 
  DATA %>%  pivot_longer(nt:sdc, 
                         names_to = c(".value","group"),
                         names_pattern = "(n|m|sd)(t|c)") 

left_join(data2 %>% filter(time ! = "pre"),
          data2 %>% filter(time = = "pre"),
          by = c("study","group"),
          suffix= c("post","pre") ) %>% 
  select(study, time = timepost, group, npre, npost, mpre, mpost, sdpre,sdpost,
         outcome = outcomepost)
#> # A tibble: 10 × 10
#>    study time  group  npre npost  mpre mpost sdpre sdpost outcome
#>    <int> <chr> <chr> <int> <int> <dbl> <dbl> <dbl>  <dbl> <chr>  
#>  1     1 post1 t        28    28  0.89  5.07  1.4    3.2  Conv   
#>  2     1 post1 c        58    58  1.22  3.52  1.76   2.58 Conv   
#>  3     1 post2 t        28    28  0.89  3.64  1.4    3.15 Conv   
#>  4     1 post2 c        58    58  1.22  2.86  1.76   2.8  Conv   
#>  5     2 post1 t        38    38  1.89  4.07  0.4    2.2  fram   
#>  6     2 post1 c        48    48  2.22  2.52  0.76   1.58 fram   
#>  7     3 post1 t        NA    31 NA     2.07 NA      1.2  voca   
#>  8     3 post1 c        NA    18 NA     1.52 NA      0.58 voca   
#>  9     3 post2 t        NA    32 NA     3.07 NA      1.12 voca   
#> 10     3 post2 c        NA    18 NA     2.32 NA      9.85 voca

Created on 2024-05-07 with reprex v2.0.2

Использование join потенциально может быть более элегантным, но вот подход без него. При необходимости может дать некоторую регулировку.

Подготовка ДАННЫХ путем filterобработки исследований без pre и добавления групп в pre, чтобы можно было назначать pre и postX в случае, если postX больше.

library(dplyr)
library(tidyr)
library(stringr)

DATA_prep <- DATA %>% 
  filter(any(time == "pre"), .by = study) %>% 
  mutate(pgrp = if_else(time == "pre", 
                  max(as.numeric(str_extract(time, ".+(\\d+)$", 
                  group=1)), na.rm=T), 1),
         grp = time == "pre", .by = study) %>% 
  uncount(pgrp) %>% 
  mutate(time = if_else(time == "pre", paste0(time, cumsum(grp)), time), 
         grp = sub(".*(\\d+)$", "\\1", time), .by = c(study, grp))

summarizeобработка и unnestобработка данных посредством групповой ассоциации, сгенерированной из имен переменных в более длинной форме.

library(rlang)

DATA_prep %>% 
  pivot_longer(-c(study, time, outcome, grp)) %>% 
  mutate(group = sub(".*(.$)", "\\1", name), 
         name = sub("^(.*)[tc]$", "\\1", name)) %>% 
  pivot_wider() %>% 
  mutate(m = set_names(m, sub("\\d+", "", time)), 
         sd = set_names(sd, sub("\\d+", "", time))) %>% 
  summarize(time = paste(time, collapse = "-"), 
            m = list(m), 
            sd = list(sd), 
            outcome = unique(outcome), .by = c(study, group, grp, n)) %>% 
  unnest_wider(c(m, sd), names_sep = "") %>% 
  select(-grp)

выход

  study group     n time        mpre mpost sdpre sdpost outcome
  <int> <chr> <dbl> <chr>      <dbl> <dbl> <dbl>  <dbl> <chr>  
1     1 t        28 pre1-post1  0.89  5.07  1.4    3.2  Conv   
2     1 c        58 pre1-post1  1.22  3.52  1.76   2.58 Conv   
3     1 t        28 pre2-post2  0.89  3.64  1.4    3.15 Conv   
4     1 c        58 pre2-post2  1.22  2.86  1.76   2.8  Conv   
5     2 t        38 pre1-post1  1.89  4.07  0.4    2.2  fram   
6     2 c        48 pre1-post1  2.22  2.52  0.76   1.58 fram

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