группировать по последовательности событий и получать сводную статистику по каждой последовательности - PullRequest
0 голосов
/ 25 февраля 2019

У меня есть data.frame с журналом последовательностей событий.Здесь последовательность 1 состоит из события A, затем B, затем C, каждое из которых начинается с определенной отметки времени (в секундах).

df=data.frame(id=runif(10, 1e6, 1e7), sequence = c(1,1,1,2,2,3,3,3,4,4), event=c("A", "B", "C", "B", "C", "A", "B", "C", "B", "C"), starts_at=c(20,22,24,20,30,20,21,23,20,40))

Я хочу сгруппировать мой data.frame по типу последовательности(Есть десятки типов, длиной от 2 до 6): A-> B-> C или B-> C, а затем получить некоторые результаты по этим типам.Желаемый результат будет:

####                      sequence_type number.appearances mean.delay.between.events
####                    1           ABC                  2                   1.5 / 2
####                    2            BC                  2                        15

В последнем столбце «средняя задержка» будет строка, составленная из среднего времени разницы между последовательными событиями в последовательности: в последовательности ABC среднее значение между A составляет 1,5 секунды.и B, и 2 между B и C. Я также подумал о "распределении" каждой средней разности в новом столбце diff.1, diff.2 ..., но кажется сложным, поскольку последовательности имеют различную длину.Хотя я открыт для разных способов подачи этой информации ..

До сих пор я придумал:

library(dplyr)
df %>% group_by(sequence) %>% arrange(starts_at) %>% summarise(sequence_type = paste0(event, collapse="")) %>% group_by(sequence_type) %>% tally

Я не нашел, как выполнить вторую часть.Спасибо за помощь ...

Ответы [ 2 ]

0 голосов
/ 25 февраля 2019

Не красиво, но работает

tmp<-df %>% group_by(sequence) %>% dplyr::arrange(sequence, starts_at) %>%  dplyr::mutate(seq_row_num=dplyr::row_number(), lead_starts_at=dplyr::lead(starts_at, n = 1)) %>% base::as.data.frame()
tmp<- tmp %>% dplyr::group_by(sequence) %>% mutate(max_seq_len=max(seq_row_num)) %>% base::as.data.frame()
tmp$seq_len_id<- paste0(tmp$sequence, tmp$max_seq_len)
tmp$next_seq_val<- tmp$seq_row_num + 1
tmp$next_seq_val<- base::ifelse(tmp$next_seq_val >= tmp$max_seq_len, tmp$max_seq_len, tmp$next_seq_val)
tmp_seq_labels<- stats::aggregate(tmp$event, list(tmp$seq_len_id), paste, collapse='')
tmp<- base::merge(tmp, tmp_seq_labels, by.x="seq_len_id", by.y="Group.1")
colnames(tmp)[which(colnames(tmp)=="x")]<- "seq_group"
tmp$within_group_step<-"ZZ"


tmp$within_group_step<- base::ifelse(tmp$seq_row_num != tmp$max_seq_len, substr(tmp$seq_group, start = tmp$seq_row_num, stop =tmp$next_seq_val), tmp$within_group_step)
tmp$within_step_by_group_id<- paste0(tmp$seq_group, tmp$within_group_step)
tmp$time_diff<- 0
tmp$time_diff<- base::ifelse(!is.na(tmp$lead_starts_at), tmp$lead_starts_at - tmp$starts_at, tmp$time_diff)

res<- stats::aggregate(time_diff ~ within_step_by_group_id + seq_group + within_group_step, data=tmp, FUN=mean)
drops<- grep(pattern = "ZZ", x = res$within_step_by_group_id)
if(length(drops)>=1){
  res<- res[-drops,]
}


colnames(res)<- c("Full_Group_Pattern", "Group_Pattern", "Sub_Group_Pattern", "Mean_Time_Difference")
res<- res %>% dplyr::group_by(Group_Pattern) %>%
  dplyr::mutate(Number_of_Appearances=n()) %>% base::as.data.frame()

Вот результат: enter image description here

0 голосов
/ 25 февраля 2019

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

library(zoo)
df=data.frame(id=runif(14, 1e6, 1e7), sequence = c(1,1,1,2,2,3,3,3,4,4,5,5,5,5), 
              event=c("A", "B", "C", "B", "C", "A", "B", "C", "B", "C","A","B","C","D"), 
              starts_at=c(20,22,24,20,30,20,21,23,20,40,20,22,21,15))
ayuda_seq = sapply(df$sequence, function(x) paste0(df[df$sequence == x,3],collapse = ""))

, а затем вы просто циклически просматриваете уникальные последовательности и генерируете подпоследовательность для каждого из 2 элементов.

vec_means = NULL
for(x in unique(ayuda_seq)){
  data_temp = df[ayuda_seq == x,]
  diff_temp = diff(data_temp$starts_at)
  temp_sub = apply(rollapply(data_temp[,3],FUN = paste0,width = 2),1,paste0,collapse = "")
  mean_temp = aggregate(diff_temp,by = list(temp_sub),mean)
  if(all(!duplicated(temp_sub))){
    averages = paste0(mean_temp[,2],collapse = " / ")
  } else{
    averages = paste0(mean_temp[match(temp_sub[duplicated(temp_sub)],mean_temp[,1]),2],collapse = " / ")
  }
  vec_means = c(vec_means,averages)
}


df_res = data.frame(sequence_type = unique(ayuda_seq),
                    number.appearances = as.numeric(table(ayuda_seq)/nchar(unique(ayuda_seq))),
                    mean.delay.between.events = vec_means)

переменная temp_sub будет иметь различные комбинации внутри исходной строки, которую вы зацикливаете.В случае "ABC" возможна комбинация «CA», которая не учитывается, поскольку она уникальна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...