Свяжите строки и выполните левое соединение из набора конвейерных списков, используя метод tidyverse

Вот dput() деконструкция данных.

library(tidyverse)

structure(list(L1 = c("Age Class", "Age Class", "Age Class", 
"Age Class", "Gender", "Gender", "Gender", "Age Class", "Age Class", 
"Age Class", "Gender", "Gender", "Age Class", "Age Class", "Age Class", 
"Gender"), L2 = c("Older Youth", "Older Youth", "Younger Youth", 
"Younger Youth", "Female", "Female", "Female", "Younger Youth", 
"Older Youth", "Older Youth", "Male", "Male", "Younger Youth", 
"Older Youth", "Older Youth", "Female"), scr = c(0.78125, 0.90625, 
0.90625, 0.6875, 0.875, 0.78125, 1, 0.65625, 0.75, 0.59375, 0.8125, 
0.75, 0.65625, 0.6875, 0.75, 0.75)), row.names = c(NA, -16L), class = "data.frame")

  1. Я хочу использовать медианную и стандартную ошибку в качестве общей статистики.

  2. Снова выполните медианную и стандартную ошибку, сгруппировав L1 и L2.

  3. Выполните тест Уилкоксона в пределах L1, поскольку он содержит 2 фактора для каждой группы.

  4. Объедините эти три списка: а) на bind_rows() из результатов шагов 1 и 2. Затем left_join() значения p.values ​​(шаг 3) с набором данных.

Желаемый конечный результат будет выглядеть как на картинке ниже:

Я попытался создать list() для каждого из шагов внутри dplyr, но обработка list(), то есть выбор или фильтрация в dplyr или конвейерной среде, является громоздкой. Тем не менее, следующий фрагмент работает, но я хочу максимально сократить обработку списков. Особенно вторую половину кода, я думаю, можно сократить или упростить.

df %>% 
  list(
    a = {.} %>% mutate(L1 = "All", L2 = "All") %>% summarise(mdn=median(scr), se=(sd(scr)/sqrt(length(scr))), .by = c(L1, L2)),
    b = {.} %>% summarise(mdn=median(scr), se=(sd(scr)/sqrt(length(scr))), .by = c(L1, L2)),
    c = {.} %>% summarise(pv= wilcox.test(scr~L2)$p.value, .by = L1)) %>% 
  list(
    d= {.} %>% keep(names(.) %in% c('a','b')) %>% bind_rows(), #Reduce codes from this line
    c= {.} %>% pluck("c")) %>% 
  keep(names(.) %in% c('c','d')) %>%
  reduce(left_join, by = "L1") #to this line

Хотел бы знать, есть ли какая-либо возможность вложения кадров данных. Любой purrr::map() способ сокращения скриптов/текстов.

Существует три разные операции с разным набором переменных, поэтому purrr::map() может нечего предложить. Какая мотивация делать это с list вместо просто bind_rows( "a", left_join( "b", "c" ))?

Adriano Mello 08.04.2024 13:41

Спасибо @AdrianoMello за ответ. Теоретически я хочу, чтобы это было именно так, но с объектом list() это не работает. К вашему сведению, на самом деле после первой операции создается 4 вложенных объекта/элемента. Один — набор данных, а остальные 3 — a, b и c.

Salty 08.04.2024 14:23

Я думаю, что мой вопрос был неясен (извините за это). Я имею в виду: почему вы хотите использовать list, когда bind_rows( a left_join(b, c)) обеспечивает ожидаемый результат (здесь это сработало)? Будут ли в качестве входных данных для этих операций использоваться другие наборы данных?

Adriano Mello 08.04.2024 14:46

На самом деле я хотел, чтобы один кусок конвейерного кода делал все. Обычно я избегаю создания множества объектов в глобальной среде. Однако нашел решение и ответил в теме.

Salty 09.04.2024 11:50
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
4
68
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

По мнению Адриано, мне кажется, что самый простой способ сделать это (безусловно) - просто выполнить эти три очень разные операции отдельно, а затем связать результаты вместе:

# Overall statistics
out_1 <- df %>%
  summarize(
    mdn = median(scr),
    se = sd(scr) / sqrt(n())
  ) %>%
  mutate(
    L1 = "All", 
    L2 = "All"
  )

# Statistics by group
out_2 <- df %>%
  group_by(L1, L2) %>%
  summarize(
    mdn = median(scr),
    se = sd(scr) / sqrt(n())
  )

# Wilcoxon test
out_3 <- df %>%
  group_by(L1) %>%
  summarize(
    pv = wilcox.test(scr ~ L2)$p.value
  )

# Combine
out <- out_1 %>%
  bind_rows(out_2) %>%
  left_join(out_3)

       mdn         se        L1            L2        pv
1 0.750000 0.02702097       All           All        NA
2 0.750000 0.04224854 Age Class   Older Youth 0.5894851
3 0.671875 0.06034703 Age Class Younger Youth 0.5894851
4 0.828125 0.05615588    Gender        Female 0.6385921
5 0.781250 0.03125000    Gender          Male 0.6385921

Если вы собираетесь делать это неоднократно, вы можете сделать из этого функцию.

Или, если вы хотите сделать все это в одном канале и вас устраивает, что вывод будет в немного другом формате:

df %>%
  mutate(
    mdn_overall = median(scr),
    se_overall = sd(scr) / sqrt(n())
  ) %>%
  group_by(L1) %>%
  mutate(
    pv = wilcox.test(scr ~ L2)$p.value
  ) %>%
  group_by(L1, L2, mdn_overall, se_overall, pv) %>%
  summarize(
    mdn_group = median(scr),
    se_group = sd(scr) / sqrt(n())
  )

  L1        L2            mdn_overall se_overall    pv mdn_group se_group
  <chr>     <chr>               <dbl>      <dbl> <dbl>     <dbl>    <dbl>
1 Age Class Older Youth          0.75     0.0270 0.589     0.75    0.0422
2 Age Class Younger Youth        0.75     0.0270 0.589     0.672   0.0603
3 Gender    Female               0.75     0.0270 0.639     0.828   0.0562
4 Gender    Male                 0.75     0.0270 0.639     0.781   0.0312

Большое спасибо @ila за усилия. К счастью, я нашел решение и ответил в теме.

Salty 09.04.2024 11:44

Теперь мы можем сгруппировать его внутри summarise и mutate с помощью .by = ... . Кажется, это более безопасный вариант для последовательных операций (ИМХО). При использовании group_by всегда полезно ungroup позже или использовать summarise( .groups = ... ).

Adriano Mello 09.04.2024 14:57
Ответ принят как подходящий

Использование %$% вместо %>% (из magrittr) сохранит независимость данных и не будет принимать первый аргумент в канал, и, следовательно, будет достаточно просто выполнить %$% left_join(bind_rows(.$a, .$b), .$c) так же, как обычный способ фрейма данных.

library(magrittr)
df %$% 
  list(
    a = {.} %>% mutate(L1 = "All", L2 = "All") %>% summarise(mdn=median(scr), se=(sd(scr)/sqrt(length(scr))), .by = c(L1, L2)),
    b = {.} %>% summarise(mdn=median(scr), se=(sd(scr)/sqrt(length(scr))), .by = c(L1, L2)),
    c = {.} %>% summarise(pv= wilcox.test(scr~L2)$p.value, .by = L1)
    ) %$% 
  left_join(bind_rows(.$a, .$b), .$c) 

Мне очень понравилось ваше собственное решение, я приму его к сведению!

Adriano Mello 09.04.2024 14:51

Что я имел в виду:

new_df <- df %>% 
  summarise(
    L1 = "All", L2 = "All", 
    mdn = median(scr), 
    se=(sd(scr)/sqrt(length(scr)))) %>% 
  
  bind_rows(
    df %>% 
      summarise(
        .by = c(L1, L2), 
        mdn = median(scr), 
        se = (sd(scr)/sqrt(length(scr)))) %>% 
      
      left_join(
        df %>% 
          summarise(
            .by = L1,
            pv = wilcox.test(scr~L2)$p.value), 
        by = "L1"))

Выход:

> new_df
         L1            L2      mdn         se        pv
1       All           All 0.750000 0.02702097        NA
2 Age Class   Older Youth 0.750000 0.04224854 0.5894851
3 Age Class Younger Youth 0.671875 0.06034703 0.5894851
4    Gender        Female 0.828125 0.05615588 0.6385921
5    Gender          Male 0.781250 0.03125000 0.6385921

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