Копирование значений из одного подмножества во все остальные для выбранных столбцов с помощью dplyr

У меня есть фрейм данных (простой пример ниже), в котором каждый пользователь заполняет анкету разное количество раз, и каждое заполнение анкеты приводит к строке в фрейме данных. В моем простом примере у пользователей A, C и D есть записи за 5 дней, а у пользователя B записи только за 4:

 > df
   UserId Days_From_First_Use Q1 Q2 Q3
1          A                   0  3  2  1
2          A                   1  1  0  0
3          A                   2  1  1  0
4          A                   3  0  2  0
5          A                   4  1  1  1
6          B                   0  4  8  2
7          B                   2  2  2  1
8          B                   4  5  6  5
9          B                   5  4  5  5
10         C                   0  5  7  2
11         C                   1  2  2  2
12         C                   2  5  5  4
13         C                   3  6  5  3
14         C                   4  6  6  4
15         D                   0  5  3  5
16         D                   1  5  3  4
17         D                   2  4  2  6
18         D                   3  0  0  1
19         D                   4  1  1  1

Теперь я вычисляю волатильность временного ряда для каждого пользователя следующим образом:

> df <- df %>% 
+     group_by(UserId) %>%
+     mutate(across(all_of(c("Q1", "Q2", "Q3")), sd,.names = paste0("Sigma_", "{.col}"))) %>%
+     ungroup()
> df
# A tibble: 19 x 8
   UserId Days_From_First_Use    Q1    Q2    Q3 Sigma_Q1 Sigma_Q2 Sigma_Q3
   <fct>                <int> <int> <int> <int>    <dbl>    <dbl>    <dbl>
 1 A                        0     3     2     1     1.10    0.837    0.548
 2 A                        1     1     0     0     1.10    0.837    0.548
 3 A                        2     1     1     0     1.10    0.837    0.548
 4 A                        3     0     2     0     1.10    0.837    0.548
 5 A                        4     1     1     1     1.10    0.837    0.548
 6 B                        0     4     8     2     1.26    2.5      2.06 
 7 B                        2     2     2     1     1.26    2.5      2.06 
 8 B                        4     5     6     5     1.26    2.5      2.06 
 9 B                        5     4     5     5     1.26    2.5      2.06 
10 C                        0     5     7     2     1.64    1.87     1    
11 C                        1     2     2     2     1.64    1.87     1    
12 C                        2     5     5     4     1.64    1.87     1    
13 C                        3     6     5     3     1.64    1.87     1    
14 C                        4     6     6     4     1.64    1.87     1    
15 D                        0     5     3     5     2.35    1.30     2.30 
16 D                        1     5     3     4     2.35    1.30     2.30 
17 D                        2     4     2     6     2.35    1.30     2.30 
18 D                        3     0     0     1     2.35    1.30     2.30 
19 D                        4     1     1     1     2.35    1.30     2.30 

Теперь начинается часть, которая доставляет мне проблемы: я хотел бы вычислить медиану sd для всех пользователей, чтобы позволить мне идентифицировать два подмножества пользователей с медианой выше и ниже медианы sd. Я не могу просто вычислить медиану sd по всем строкам, потому что количество наблюдений для каждого пользователя разное. Однако я могу сгруппировать по Days_From_First_Use а затем вычислить медиану sd для каждого дня. Поскольку у всех пользователей есть день 0 (их самый первый день), медиана sd в этот день — это значение, которое мне нужно. Итак, я набираю:

> df <- df %>% 
+     group_by(UserId) %>%
+     mutate(across(all_of(c("Q1", "Q2", "Q3")), sd,.names = paste0("Sigma_", "{.col}"))) %>%
+     ungroup() %>%
+     group_by(Days_From_First_Use) %>%
+     mutate(across(all_of(paste0("Sigma_", c("Q1", "Q2", "Q3"))), median ,.names = paste0("Median_", "{.col}"))) %>%
+     ungroup()
>     
> df
# A tibble: 19 x 11
   UserId Days_From_First_Use    Q1    Q2    Q3 Sigma_Q1 Sigma_Q2 Sigma_Q3 Median_Sigma_Q1 Median_Sigma_Q2 Median_Sigma_Q3
   <fct>                <int> <int> <int> <int>    <dbl>    <dbl>    <dbl>           <dbl>           <dbl>           <dbl>
 1 A                        0     3     2     1     1.10    0.837    0.548            1.45            1.59            1.53
 2 A                        1     1     0     0     1.10    0.837    0.548            1.64            1.30            1   
 3 A                        2     1     1     0     1.10    0.837    0.548            1.45            1.59            1.53
 4 A                        3     0     2     0     1.10    0.837    0.548            1.64            1.30            1   
 5 A                        4     1     1     1     1.10    0.837    0.548            1.45            1.59            1.53
 6 B                        0     4     8     2     1.26    2.5      2.06             1.45            1.59            1.53
 7 B                        2     2     2     1     1.26    2.5      2.06             1.45            1.59            1.53
 8 B                        4     5     6     5     1.26    2.5      2.06             1.45            1.59            1.53
 9 B                        5     4     5     5     1.26    2.5      2.06             1.26            2.5             2.06
10 C                        0     5     7     2     1.64    1.87     1                1.45            1.59            1.53
11 C                        1     2     2     2     1.64    1.87     1                1.64            1.30            1   
12 C                        2     5     5     4     1.64    1.87     1                1.45            1.59            1.53
13 C                        3     6     5     3     1.64    1.87     1                1.64            1.30            1   
14 C                        4     6     6     4     1.64    1.87     1                1.45            1.59            1.53
15 D                        0     5     3     5     2.35    1.30     2.30             1.45            1.59            1.53
16 D                        1     5     3     4     2.35    1.30     2.30             1.64            1.30            1   
17 D                        2     4     2     6     2.35    1.30     2.30             1.45            1.59            1.53
18 D                        3     0     0     1     2.35    1.30     2.30             1.64            1.30            1   
19 D                        4     1     1     1     2.35    1.30     2.30             1.45            1.59            1.53

Для справки, (неправильные) медианы по всему кадру данных составляют 1,64, 1,30 и 1 соответственно, а правильные медианы - 1,45, 1,59 и 1,53.

Теперь я хочу заменить все медианы sd на sd в день 0. Как только я это сделаю, я смогу правильно разделить фрейм данных на подмножества с высоким sd и низким sd.

Вопрос: Как мне скопировать правильные медианы дня 0 в эти три столбца, а затем создать новые столбцы с подмножествами Low sd и High sd, определенными sd пользователя относительно средней волатильности для каждого вопроса?

С уважением и заранее с большой благодарностью

Томас Филипс

Стоит ли изучать 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
149
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Я думаю, вы могли бы вычислить правильную медиану для каждого пользователя, используя только первую запись для каждого пользователя, а затем left_join.

df = 
  tibble(
    UserId = c("A", "A", "A", "A", "A", "B", "B", "B", "B", "C", "C", "C", "C", "C", "D", "D", "D", "D", "D"),
    DFFU = c(0, 1, 2, 3, 4, 0, 2, 4, 5, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4),
    Q1 = c(3, 1, 1, 0, 1, 4, 2, 5, 4, 5, 2, 5, 6, 6, 5, 5, 4, 0, 1),
    Q2 = c(2,0,1,2,1,8,2,6,5,7,2,5,5,6,3,3,2,0,1),
    Q3 = c(1,0,0,0,1,2,1,5,5,2,2,4,3,4,5,4,6,1,1)
  )

df <- df %>% 
  group_by(UserId) %>%
  mutate(across(all_of(c("Q1", "Q2", "Q3")), sd,.names = paste0("Sigma_", "{.col}"))) %>%
  ungroup()

df %>%
  filter(DFFU == 0) %>%
  transmute(UserId = UserId, across(all_of(paste0("Sigma_", c("Q1", "Q2", "Q3"))), median ,.names = paste0("Median_", "{.col}"))) %>%
  {left_join(df, .)}

Урожайность:

> df
# A tibble: 19 x 11
   UserId  DFFU    Q1    Q2    Q3 Sigma_Q1 Sigma_Q2 Sigma_Q3 Median_Sigma_Q1 Median_Sigma_Q2 Median_Sigma_Q3
   <chr>  <dbl> <dbl> <dbl> <dbl>    <dbl>    <dbl>    <dbl>           <dbl>           <dbl>           <dbl>
 1 A          0     3     2     1     1.10    0.837    0.548            1.45            1.59            1.53
 2 A          1     1     0     0     1.10    0.837    0.548            1.45            1.59            1.53
 3 A          2     1     1     0     1.10    0.837    0.548            1.45            1.59            1.53
 4 A          3     0     2     0     1.10    0.837    0.548            1.45            1.59            1.53
 5 A          4     1     1     1     1.10    0.837    0.548            1.45            1.59            1.53
 6 B          0     4     8     2     1.26    2.5      2.06             1.45            1.59            1.53
 7 B          2     2     2     1     1.26    2.5      2.06             1.45            1.59            1.53
 8 B          4     5     6     5     1.26    2.5      2.06             1.45            1.59            1.53
 9 B          5     4     5     5     1.26    2.5      2.06             1.45            1.59            1.53
10 C          0     5     7     2     1.64    1.87     1                1.45            1.59            1.53
11 C          1     2     2     2     1.64    1.87     1                1.45            1.59            1.53
12 C          2     5     5     4     1.64    1.87     1                1.45            1.59            1.53
13 C          3     6     5     3     1.64    1.87     1                1.45            1.59            1.53
14 C          4     6     6     4     1.64    1.87     1                1.45            1.59            1.53
15 D          0     5     3     5     2.35    1.30     2.30             1.45            1.59            1.53
16 D          1     5     3     4     2.35    1.30     2.30             1.45            1.59            1.53
17 D          2     4     2     6     2.35    1.30     2.30             1.45            1.59            1.53
18 D          3     0     0     1     2.35    1.30     2.30             1.45            1.59            1.53
19 D          4     1     1     1     2.35    1.30     2.30             1.45            1.59            1.53

Одна из причин, по которой ваш анализ становится таким странным, заключается в том, что вы нарушаете принципы аккуратности данных. В исходном наборе данных каждая строка представляет один опрос, но стандартное отклонение применяется к каждому учащемуся, а не к каждому опросу. Таким образом, значения стандартного отклонения должны отображаться в таблице с 5 строками, по одной строке для каждого учащегося. Тогда медиана представляет собой совокупность студентов. Существует только одна популяция, поэтому должна быть только одна строка. Поэтому я бы рекомендовал:

sd_df <- 
  df %>%
  group_by(UserId) %>%
  summarize(
    across(
      all_of(c("Q1", "Q2", "Q3")), 
      .fns = sd, 
      .names = paste0("Sigma_", "{.col}")
    )
  )

median_sd_df <-
  sd_df %>%
  summarize(
    across(
      all_of(paste0("Sigma_", c("Q1", "Q2", "Q3"))), 
      .fns = median, 
      .names = paste0("Sigma_", "{.col}")
    ),
    n = n()
  )

что дает вам:

> sd_df
# A tibble: 4 x 5
  UserId Sigma_Q1 Sigma_Q2 Sigma_Q3     n
  <chr>     <dbl>    <dbl>    <dbl> <int>
1 A          1.10    0.837    0.548     5
2 B          1.26    2.5      2.06      4
3 C          1.64    1.87     1         5
4 D          2.35    1.30     2.30      5

>  median_sd_df
# A tibble: 1 x 3
  Median_Sigma_Q1 Median_Sigma_Q2 Median_Sigma_Q3
            <dbl>           <dbl>           <dbl>
1            1.45            1.59            1.53

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

Thomas Philips 21.12.2020 00:58

@ThomasPhilips, просто чтобы уточнить, надеюсь, я не был критичен. Вы, конечно, не можете контролировать, как часто люди заполняют опрос! Конечно, тот факт, что размер вашей выборки изменчив, имеет некоторые статистические последствия, но данные таковы, каковы они есть, и мы все делаем все возможное! Для прозрачности вы можете рассмотреть возможность сообщения размера вашей выборки по отдельным лицам, когда вы записываете свои результаты. Я изменю свой ответ, чтобы включить эту информацию. ХТХ!

Geoffrey Poole 21.12.2020 05:13

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

Thomas Philips 22.12.2020 02:07

Решил это, но неуклюжим способом: сначала сгруппировать по Days_From_First_Use, использовать тот факт, что у нас есть все пользователи в День 0, вычислить медиану, извлечь первую строку в другой фрейм данных, а затем перезаписать все соответствующие строки этим новый фрейм данных.

> df_median_sigma <- df %>% 
                       arrange(Days_From_First_Use) %>%
                       select(starts_with("Median_Sigma")) %>% 
                       filter(row_number( ) == 1)
> df_median_sigma
# A tibble: 1 x 3
  Median_Sigma_Q1 Median_Sigma_Q2 Median_Sigma_Q3
            <dbl>           <dbl>           <dbl>
1            1.45            1.59            1.53

Наконец, перезапишите все соответствующие столбцы в df правильными медианами:

    > df[paste0("Median_Sigma_", c("Q1", "Q2", "Q3"))] <- df_median_sigma
> df
# A tibble: 19 x 11
   UserId Days_From_First_Use    Q1    Q2    Q3 Sigma_Q1 Sigma_Q2 Sigma_Q3 Median_Sigma_Q1 Median_Sigma_Q2 Median_Sigma_Q3
   <fct>                <int> <int> <int> <int>    <dbl>    <dbl>    <dbl>           <dbl>           <dbl>           <dbl>
 1 A                        0     3     2     1     1.10    0.837    0.548            1.45            1.59            1.53
 2 A                        1     1     0     0     1.10    0.837    0.548            1.45            1.59            1.53
 3 A                        2     1     1     0     1.10    0.837    0.548            1.45            1.59            1.53
 4 A                        3     0     2     0     1.10    0.837    0.548            1.45            1.59            1.53
 5 A                        4     1     1     1     1.10    0.837    0.548            1.45            1.59            1.53
 6 B                        0     4     8     2     1.26    2.5      2.06             1.45            1.59            1.53
 7 B                        2     2     2     1     1.26    2.5      2.06             1.45            1.59            1.53
 8 B                        4     5     6     5     1.26    2.5      2.06             1.45            1.59            1.53
 9 B                        5     4     5     5     1.26    2.5      2.06             1.45            1.59            1.53
10 C                        0     5     7     2     1.64    1.87     1                1.45            1.59            1.53
11 C                        1     2     2     2     1.64    1.87     1                1.45            1.59            1.53
12 C                        2     5     5     4     1.64    1.87     1                1.45            1.59            1.53
13 C                        3     6     5     3     1.64    1.87     1                1.45            1.59            1.53
14 C                        4     6     6     4     1.64    1.87     1                1.45            1.59            1.53
15 D                        0     5     3     5     2.35    1.30     2.30             1.45            1.59            1.53
16 D                        1     5     3     4     2.35    1.30     2.30             1.45            1.59            1.53
17 D                        2     4     2     6     2.35    1.30     2.30             1.45            1.59            1.53
18 D                        3     0     0     1     2.35    1.30     2.30             1.45            1.59            1.53
19 D                        4     1     1     1     2.35    1.30     2.30             1.45            1.59            1.53

Работает, но немного коряво. Я подозреваю, что у dplyr есть более элегантный способ сделать это, но я не смог его найти.

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