как подсчитать события в пределах нескольких интервалов для каждого фактора в R?

#r #loops #datetime #intervals

Вопрос:

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

Ниже приведен MWE:

 library(lubridate)  myintervals lt;- c(dmy_hms( "01/01/2000 08:00:00", "25/02/2000 09:00:00", "01/03/2000 10:00:00", "30/04/2000 11:00:00", "01/05/2000 12:00:00", "30/06/2000 13:00:00", "01/07/2000 14:00:00", "30/08/2000 15:00:00", "01/09/2000 16:00:00", "30/10/2000 17:00:00"))  mystations lt;- c("A","B","C","A","B","C","A","B","C","D")  mydata lt;- data.frame(myintervals,mystations)   myintervals mystations  |1 2000-01-01 08:00:00 A  |2 2000-02-25 09:00:00 B  |3 2000-03-01 10:00:00 C  |4 2000-04-30 11:00:00 A  |5 2000-05-01 12:00:00 B  |6 2000-06-30 13:00:00 C  |7 2000-07-01 14:00:00 A  |8 2000-08-30 15:00:00 B  |9 2000-09-01 16:00:00 C  |10 2000-10-30 17:00:00 D  

Вот я создаю обнаружение

 date.time lt;- c(dmy_hms( "31/12/1999 08:00:00", "24/02/2000 09:00:00", "25/02/2000 08:00:00", "26/02/2000 10:00:00", "27/02/2000 11:00:00", "01/03/2000 10:00:00", "10/03/2000 22:00:00", "20/03/2000 23:00:00", "01/04/2000 10:00:00", "20/04/2000 20:00:00", "25/04/2000 08:00:00", "30/04/2000 10:00:00", "01/05/2000 12:00:00", "10/05/2000 20:00:00", "20/05/2000 08:00:00", "30/06/2000 13:00:00", "10/07/2000 10:00:00", "20/07/2000 20:00:00", "30/08/2000 15:00:00", "01/09/2000 16:00:00"))  mydetections lt;- data.frame(date.time=date.time,mystations=mystations)   date.time mystations  |1 1999-12-31 08:00:00 A  |2 2000-02-24 09:00:00 B  |3 2000-02-25 08:00:00 C  |4 2000-02-26 10:00:00 A  |5 2000-02-27 11:00:00 B  |6 2000-03-01 10:00:00 C  |7 2000-03-10 22:00:00 A  |8 2000-03-20 23:00:00 B  |9 2000-04-01 10:00:00 C  |10 2000-04-20 20:00:00 D  |11 2000-04-25 08:00:00 A  |12 2000-04-30 10:00:00 B  |13 2000-05-01 12:00:00 C  |14 2000-05-10 20:00:00 A  |15 2000-05-20 08:00:00 B  |16 2000-06-30 13:00:00 C  |17 2000-07-10 10:00:00 A  |18 2000-07-20 20:00:00 B  |19 2000-08-30 15:00:00 C  |20 2000-09-01 16:00:00 D   

Исходные данные для каждого интервала находятся здесь:

 myorigins lt;- data.frame(myintervals=c( dmy_hms("01/01/1970 00:00:00","01/04/1970 00:00:00","01/08/1970 00:00:00","01/12/1970 00:00:00")),mystations=c(unique(mydata$mystations)))  

The expected output is this:

 myintervals mystation value 1 1970-01-01 00:00:00 UTC--2000-01-01 08:00:00 UTC A 1 2 2000-01-01 08:00:00 UTC--2000-04-30 11:00:00 UTC A 3 3 2000-04-30 11:00:00 UTC--2000-07-01 14:00:00 UTC A 1 4 1970-04-01 00:00:00 UTC--2000-02-25 09:00:00 UTC B 1 5 2000-02-25 09:00:00 UTC--2000-05-01 12:00:00 UTC B 3 6 2000-05-01 12:00:00 UTC--2000-08-30 15:00:00 UTC B 2 7 1970-08-01 00:00:00 UTC--2000-03-01 10:00:00 UTC C 2 8 2000-03-01 10:00:00 UTC--2000-06-30 13:00:00 UTC C 3 9 2000-06-30 13:00:00 UTC--2000-09-01 16:00:00 UTC C 1 10 1970-12-01 00:00:00 UTC--2000-10-30 17:00:00 UTC D 1  

Чего я смог добиться до сих пор, так это:

 #line by line mydata lt;- add_row(mydata,myorigins) mydata lt;- arrange(mydata,mystations,myintervals) DF lt;- group_split(mydata,mystations) Y lt;- lapply(seq_along(DF), function(x) as.data.frame(DF[[x]])) names(Y) lt;- c(unique(mydata$mystations)) list2env(Y, envir = .GlobalEnv)  #splitting the detections DFD lt;- group_split(mydetections,mystations) Z lt;- lapply(seq_along(DFD), function(x) as.data.frame(DFD[[x]])) names(Z) lt;- c(paste(unique(mydata$mystations),"det",sep="")) list2env(Z, envir = .GlobalEnv)  

Я считаю, что сейчас самое время «только» строить интервалы для каждого кадра данных следующим образом:

 Aint lt;- int_diff(A$myintervals)  

и «проверка», какое обнаружение попадает в какой интервал с этим:

 myresA lt;- Adet$date.time%within%Aint  

Ясно, что я хотел бы избежать «ручного» построения интервалов для каждого df As. Как всегда, я был бы очень признателен за любую помощь или советы для получения желаемого результата. Я приношу извинения за первоначальную путаницу в этом посте.

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

1.Не было бы лучше с mydata lt;- data.frame(myintervals, mystations) этим ? Используя cbind , вы получаете character матрицу, которая разбивает ваш POSIXt на строки, похожие на числа.

2. совершенно верно @r2evans! Я собираюсь обновить код, который не имеет отношения к решению вопроса.

3. Я подозреваю, что ваш «ожидаемый результат» неверен: у вас повторяющиеся строки и многие строки отсутствуют. Должен ли результат содержать 20 строк (т. Е. соединение включено mydetections ) или 10 строк (включено mydata )?

4. Честно говоря, я не знаю, что mydata предполагается предоставить … он не используется. Должен ли ваш subset -код ссылаться mydata$ внутренне, а mydetetions$ не ? Вы делаете только ссылку [1] через [10]

5. @r2evans, еще раз поправьте. Я сожалею о допущенных ошибках. Желаемый результат теперь правильный и рассчитывается вручную.

Ответ №1:

Вот несколько вариантов для рассмотрения — надеюсь, это может быть полезно.

С помощью tidyverse вы можете добавить свой myorigins в mydata , а затем после сортировки с arrange интервалами времени (начало-конец).

Вы можете использовать fuzzy_left_join для добавления таблицы событий, совпадающей по mystations времени и месту date.time между интервалом start и end .

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

 library(tidyverse) library(fuzzyjoin) library(lubridate)  bind_rows(mydata, myorigins) %gt;%  arrange(myintervals) %gt;%  group_by(mystations) %gt;%  transmute(start = myintervals, end = lead(myintervals)) %gt;%  filter(!is.na(end)) %gt;%  fuzzy_left_join(  mydetections,  by = c("mystations", "start" = "date.time", "end" = "date.time"),  match_fun = c(`==`, `lt;`, `gt;=`)  ) %gt;%  group_by(start, end, mystations.x) %gt;%  summarise(count = n()) %gt;%  arrange(mystations.x)  

Выход

 start end mystations.x count  lt;dttmgt; lt;dttmgt; lt;chrgt; lt;intgt;  1 1970-01-01 00:00:00 2000-01-01 08:00:00 A 1  2 2000-01-01 08:00:00 2000-04-30 11:00:00 A 3  3 2000-04-30 11:00:00 2000-07-01 14:00:00 A 1  4 1970-04-01 00:00:00 2000-02-25 09:00:00 B 1  5 2000-02-25 09:00:00 2000-05-01 12:00:00 B 3  6 2000-05-01 12:00:00 2000-08-30 15:00:00 B 2  7 1970-08-01 00:00:00 2000-03-01 10:00:00 C 2  8 2000-03-01 10:00:00 2000-06-30 13:00:00 C 3  9 2000-06-30 13:00:00 2000-09-01 16:00:00 C 1 10 1970-12-01 00:00:00 2000-10-30 17:00:00 D 2  

Альтернативой для рассмотрения является использование data.table того, что было бы быстрее. Одна из функций, которая может быть полезна здесь, — foverlaps найти совпадение между датами событий и диапазонами дат.

 library(data.table)  dt lt;- rbind(myorigins, mydata) setDT(dt)  dt[, c("start", "end") := list(myintervals, lead(myintervals)), by = mystations] dt lt;- na.omit(dt, "end")  setDT(mydetections)  mydetections[,date.time.copy := copy(date.time)] setkey(mydetections, mystations, date.time, date.time.copy)  dt_ovlp lt;- foverlaps(dt,   mydetections,   by.x = c("mystations", "start", "end"),  by.y = c("mystations", "date.time", "date.time.copy"))  dt_ovlp[ , .(value = .N), by = c("mystations", "start", "end")][order(mystations, start)]  

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

1. Большое вам спасибо за предоставление вашего решения. Мне это кажется совершенным, и, конечно, это было выше моих возможностей. Я узнал кое-что еще!