У меня есть временной ряд получасовых наблюдений. Мне нужно среднее значение диапазона измерений каждого дня. Я группирую по дате и получаю правильные дневные диапазоны, но тогда все, что я могу придумать, чтобы получить скользящее среднее, работает только внутри дневных групп, а не между ними — построчно, а не по дням — и поскольку каждый день имеет только один диапазон, значение, которое я получаю, всегда снова соответствует этому диапазону. Вот один пример:
library(tidyverse)
library(zoo)
set.seed(3)
dts <- sort(sample(seq(as_datetime("2024-08-15 09:00:00 EDT"), as_datetime("2024-08-22 09:00:00 EDT"), by = "hour"), 24))
df <- tibble(dts = dts, temp = sample(10:20, 24, replace=TRUE))
df <- df %>%
mutate(date = as.Date(dts)) %>%
group_by(date) %>%
mutate(tMax = max(temp, na.rm = TRUE), tMin = min(temp, na.rm = TRUE)) %>%
mutate(range = tMax - tMin) %>%
mutate(rollRange = rollapply(range, 3, mean, fill=NA))
В реальных данных каждый день всегда намного больше наблюдений, чем дней в скользящем окне, поэтому есть только NA для начала каждого дня, а затем идентичны range
. Дополнительная сложность заключается в том, что по другим причинам в день создается случайное количество строк, поэтому я не могу просто создать свое окно obs/day * days
. Должен ли я summarize()
вынести это в отдельный фрейм данных только для того, чтобы объединить его обратно?
Приношу извинения, вот результат репрекса плюс столбец desired
, показывающий что-то вроде того, что я ищу:
dts temp date tMax tMin range rollRange desired
<dttm> <int> <date> <int> <int> <int> <dbl> <dbl>
1 2024-08-15 13:00:00 17 2024-08-15 19 17 2 NA NA
2 2024-08-15 20:00:00 19 2024-08-15 19 17 2 NA NA
3 2024-08-16 02:00:00 20 2024-08-16 20 12 8 NA 4
4 2024-08-16 04:00:00 16 2024-08-16 20 12 8 8 4
5 2024-08-16 06:00:00 12 2024-08-16 20 12 8 8 4
6 2024-08-16 20:00:00 14 2024-08-16 20 12 8 8 4
7 2024-08-16 21:00:00 16 2024-08-16 20 12 8 NA 4
8 2024-08-17 00:00:00 15 2024-08-17 17 15 2 NA 5.33
9 2024-08-17 08:00:00 17 2024-08-17 17 15 2 NA 5.33
10 2024-08-18 06:00:00 19 2024-08-18 19 13 6 NA 4.33
11 2024-08-18 10:00:00 13 2024-08-18 19 13 6 NA 4.33
12 2024-08-19 16:00:00 10 2024-08-19 15 10 5 NA 6.66
13 2024-08-19 19:00:00 12 2024-08-19 15 10 5 5 6.66
14 2024-08-19 20:00:00 15 2024-08-19 15 10 5 NA 6.66
15 2024-08-20 06:00:00 13 2024-08-20 18 13 5 NA 6.66
16 2024-08-20 08:00:00 18 2024-08-20 18 13 5 NA 6.66
17 2024-08-21 00:00:00 19 2024-08-21 19 10 9 NA 6
18 2024-08-21 01:00:00 16 2024-08-21 19 10 9 9 6
19 2024-08-21 04:00:00 19 2024-08-21 19 10 9 9 6
20 2024-08-21 08:00:00 10 2024-08-21 19 10 9 9 6
21 2024-08-21 19:00:00 18 2024-08-21 19 10 9 9 6
22 2024-08-21 21:00:00 10 2024-08-21 19 10 9 NA 6
23 2024-08-22 05:00:00 18 2024-08-22 18 14 4 NA NA
24 2024-08-22 09:00:00 14 2024-08-22 18 14 4 NA NA
@Friede Отредактировано, чтобы показать желаемое (не сказать ожидаемое...).
@Friede Ваше предложение позволяет ему более эффективно вырабатывать значения вместо NA, но оно по-прежнему рассчитывает только скользящее среднее по строкам, а не среднее скользящее среднее за день.
Извините, не могу помочь; Я не понимаю.
Да, использовать rollmean
в сводке и присоединиться обратно кажется проще всего.
roll <- df %>% # df has already been grouped
summarize(rollRange2 = first(range)) %>%
mutate(rollRange2 = rollmean(rollRange2, 3, fill = NA))
df %>%
left_join(roll, join_by(date))
Ах, наконец! Спасибо. Я предполагал, что этого будет достаточно, чтобы появился более гибкий метод, который мне почему-то не хватало, а также другие вопросы. Но нет! И я не знал об этом first()
— мог бы потратить еще несколько дней, пытаясь это выяснить.
Пожалуйста, укажите ожидаемый результат.
df |> mutate(date = as.Date(dts)) |> mutate(tMax = max(temp, na.rm = TRUE), tMin = min(temp, na.rm = TRUE), range = tMax - tMin, .by = date) |> ungroup() |> mutate(rollRange = rollapply(range, 3, mean, fill=NA))
?