Получение количества участников в комбинации групп с помощью sparklyr или dplyr

#r #apache-spark #pyspark #dplyr #sparklyr

Вопрос:

У меня есть фрейм данных spark, которым я управляю с помощью sparklyr, который выглядит следующим образом:

 input_data <- data.frame(id = c(10,10,10,20,20,30,30,40,40,40,50,60,70, 80,80,80,100,100,110,110,120,120,120,130,140,150,160,170), 
           date = c("2021-01-01","2021-01-02","2021-01-03","2021-01-01","2021-01-02","2021-01-01","2021-01-02","2021-01-02","2021-01-01","2021-01-02","2021-01-01","2021-01-02","2021-01-05","2021-01-01","2021-01-02","2021-01-03","2021-01-01","2021-01-02","2021-01-01","2021-01-02","2021-01-02","2021-01-01","2021-01-02","2021-01-01","2021-01-02","2021-01-05","2021-01-01","2021-01-05"), 
           group = c("A", "B", "C", "B", "C", "A", "C", "A", "A", "A", "C", "A","B","A", "B", "C", "B", "C", "A", "C", "A", "A", "A", "C", "A", "A", "B","A"), 
           event = c(1,1,1,0,1,0,1,0,0,1,1,1,0,1,1,1,0,1,0,1,0,0,1,1,1,1,1,0))
 

введите описание изображения здесь

Я хотел бы агрегировать данные таким образом, чтобы у меня было количество «событий» (где event == 1 ) и «не_событий» (где event == 0 ) для каждой комбинации, чтобы конечный результат выглядел следующим образом:

 data.frame(group_a = c(1,0,0,1,0,1), 
           group_b = c(0,1,0,1,1,0), 
           group_c = c(0,0,1,0,1,1), 
           event_occured = c(3,1,2,0,2,2), 
           event_not_occured = c(4,2,2,0,2,2))
 

введите описание изображения здесь

Так, например, не было комбинаций, в которых A и B были группами для одного и того же идентификатора, так что для event and получается 0 non_event . Было 4 идентификатора, в которых участвовала группа А, из которых 3 привели к ан event и 1 привели к а non_event , и так далее, и так далее.

Какой подход с использованием sparklyr (или dplyr или pyspark) позволил бы агрегировать, как описано выше? Я попробовал следующее, но я получаю точно такое же количество event , как event_not_occurred , так что я, должно быть, делаю что-то не так, но не могу точно определить это:

 combo_path_sdf <- input_data %>%
  group_by(id) %>%
  arrange(date) %>%
  mutate(order_seq = ifelse(event > 0, 1, NA)) %>%
  mutate(order_seq = lag(cumsum(ifelse(is.na(order_seq), 0, order_seq)))) %>%
  mutate(order_seq = ifelse((row_number() == 1) amp; (event > 0), -1, ifelse(row_number() == 1, 0, order_seq))) %>% 
  ungroup()

    combo_path_sdf %>%
      group_by(id, order_seq) %>%
      summarize(group_a = max(ifelse(group_a == "A", 1, 0)),
                group_b = max(ifelse(group_b == "B", 1, 0)),
                group_c = max(ifelse(group_c == "C", 1, 0)),
                events = sum(event)) %>%
      group_by(order_seq, group_a, group_b, group_c) %>% 
      summarize(event = sum(events),
                total_sequences = n()) %>%
      mutate(event_not_occured = total_sequences - event)
 

Окончательный вывод в следующем формате тоже подойдет:

 data.frame(group_a = c("A", "B", "C", "A,B", "B,C", "A,C"), 
           event_occured = c(3,1,2,1,2,2), 
           event_not_occured = c(4,2,2,1,2,2))
 

(изображение ниже для A,B неверно, должно быть 1,1, а не 0,0)
введите описание изображения здесь

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

1. Совпадают ли показанные вами данные и ожидаемый результат? Почему значение A, B group_a равно 0 для обоих типов событий? В ваших данных есть события A и B для идентификатора 10.

2. О, это ошибка, вы правы.

Ответ №1:

Следующее соответствует запрошенному вами формату вывода и обрабатывает данные так, как я понимаю, вы хотите, но (согласно комментарию @Martin Gal) не соответствует приведенному вами примеру.

 input_data %>%
  group_by(id) %>%
  summarise(group_a = max(ifelse(group == 'A', 1, 0)),
            group_b = max(ifelse(group == 'B', 1, 0)),
            group_c = max(ifelse(group == 'C', 1, 0)),
            event_occured = sum(ifelse(event == 1, 1, 0)),
            event_not_occured = sum(ifelse(event == 0, 1, 0)),
            .groups = "drop") %>%
  group_by(group_a, group_b, group_c) %>%
  summarise(event_occured = sum(event_occured),
            event_not_occured = sum(event_not_occured),
            .groups = "drop")
 

Эта идея представляет собой двухэтапный процесс обобщения. Первое обобщение создает индикатор для группы по каждому событию и подсчитывает количество событий/не событий. Второе обобщение объединяет все аналогичные группы.

Что касается кода, который вы используете, который создает одинаковое количество событий и не-событий. Взгляните на hts_combined это . Это не определено в коде, которым вы поделились, и, следовательно, ваш сценарий может считывать переменную из другого места.