#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. Большое вам спасибо за предоставление вашего решения. Мне это кажется совершенным, и, конечно, это было выше моих возможностей. Я узнал кое-что еще!