#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
это . Это не определено в коде, которым вы поделились, и, следовательно, ваш сценарий может считывать переменную из другого места.