У меня есть данные об интенсивности использования воды, которые собирались каждый час в течение многих месяцев (ниже представлена часть данных). Мне нужна первая дата, когда интенсивность была больше 900, но только если она была больше или равна 900 в течение как минимум 24 часов. Кроме того, мне нужна дата, когда вода впоследствии упала ниже 900 после последнего дня, когда вода была выше 900 в течение как минимум 24 часов. Затем мне нужно повторить, что в течение всех последующих более чем 24-часовых периодов интенсивность воды снова поднимается выше/ниже 900 на протяжении всего периода исследования. Я надеюсь избежать необходимости вручную просматривать все данные для каждого сайта.
## creates example dataframe
NoOfHours <- as.numeric(ymd_hms("2010-01-06 01:00:00") - ymd_hms("2010-01-01 07:00:00"))*24
dt<-ymd_hms("2010-01-01 00:00:00") + hours(0:NoOfHours)
intensity<-c(rep(c(0),23),rep(c(901,904),12), rep(c(660,540),10), rep(c(905,3000),10), 550, rep(c(1000,1200),13),340)
df<-data.frame(dt, intensity)
Итак, у меня должно получиться:
dt1 status
1 2010-01-01 23:00:00 start
2 2010-01-02 23:00:00 stop
3 2010-01-04 16:00:00 start
4 2010-01-05 18:00:00 stop
Извлеките эти строки с интенсивностью более 900, а затем создайте группирующую переменную g
, используя seqid
, которая предоставляет уникальный идентификатор каждой последовательной последовательности. Сократите каждую такую группу до одной строки, при этом даты первой и последней строки добавляют один час к последней. Извлеките те строки, которые представляют как минимум 24 исходные строки. Преобразуйте это в длинную форму, чтобы start
и stop
находились на разных строках, а затем выберите нужные столбцы.
library(collapse)
library(dplyr)
library(tidyr)
df %>%
filter(intensity > 900) %>%
mutate(g = seqid(dt, del = 3600)) %>%
summarize(start = first(dt), stop = last(dt) + 3600, n = n(), .by = g) %>%
filter(n >= 24) %>%
pivot_longer(start:stop, names_to = "status", values_to = "dt1") %>%
select(dt1, status)
предоставление
# A tibble: 4 × 2
dt1 status
<dttm> <chr>
1 2010-01-01 23:00:00 start
2 2010-01-02 23:00:00 stop
3 2010-01-04 16:00:00 start
4 2010-01-05 18:00:00 stop
Мы можем использовать rollapply
из zoo
, чтобы найти 24-часовые периоды, когда интенсивность превышала определенную величину, затем seqid
из collapse
, чтобы сгруппировать эти периоды и выбрать первую дату для каждого периода.
library(zoo)
library(dplyr)
library(collapse)
find_first_last <- function(df, intensity) {
df1 <- df[rollapply(df$intensity, width=24, FUN=\(z) all(z>=intensity)),] |>
mutate(id=seqid(dt, del=3600)) |>
filter(dt==first(dt), .by=id) |>
transmute(start=dt)
df1['stop'] <- df$dt[sapply(df1$start,
FUN=\(x) first(which(df$dt > x & df$intensity<intensity)))]
return(df1)
}
find_first_last(df, intensity=900)
start stop
1 2010-01-01 23:00:00 2010-01-02 23:00:00
2 2010-01-04 16:00:00 2010-01-05 18:00:00