Скользящее среднее за 10 минут до скользящего среднего за 1 час в R - PullRequest
0 голосов
/ 10 мая 2018

У меня есть набор данных о погоде в 10-минутной скользящей средней, показывающий с интервалом в 1 минуту. Я хотел бы преобразовать его в среднее значение за 1 час.

               Date   Direction   Speed
1  2017-07-06 00:01:00        93   7.3
2  2017-07-06 00:02:00        92   7.4
3  2017-07-06 00:03:00        92   7.3
4  2017-07-06 00:04:00        91   7.4
5  2017-07-06 00:05:00        91   7.3
6  2017-07-06 00:06:00        91   7.3
7  2017-07-06 00:07:00        91   7.2
8  2017-07-06 00:08:00        90   7.1
9  2017-07-06 00:09:00        90   6.9
10 2017-07-06 00:10:00        91   6.7
...
(thousands of row of data in 1 min-interval

* Направление и скорость выше в 10-минутном скользящем среднем

Для обычных встроенных функций скользящего среднего они встречают все значения окрестностей, например:

rollmean(timeLine$Speed, 60, fill=FALSE, align = "right")

приведет к броску среднего значения для каждого значения, встречающегося с n, n-1, n-2, n-3, ..., n-59.

Однако, поскольку мои необработанные данные уже являются средними за 10 минут, мне просто нужно принять значения n, n-10, n-20, n-30, n-40, n-50, чтобы преобразовать их в среднечасовое значение.

Например, если я хочу почасовые данные за 2001-07-06 10:00:00, мне просто нужно взять среднее значение для следующих значений:

  • 2001-07-06 10: 00: 00
  • 2001-07-06 09: 50: 00
  • 2001-07-06 09: 40: 00
  • 2001-07-06 09: 30: 00
  • 2001-07-06 09: 20: 00
  • 2001-07-06 09: 10: 00

Есть ли какой-нибудь способ, которым я мог бы плавно рассчитать его по R?

Заранее спасибо за помощь!

Обновление 1: вот dput (head (timeLine, 10))

structure(
  list(
    Date = structure(c(1499270460, 1499270520, 1499270580, 1499270640, 1499270700, 1499270760, 1499270820, 1499270880, 1499270940, 1499271000),
    class = c("POSIXct", "POSIXt"), tzone = "Asia/Hong_Kong"), 
  Direction = c(93L, 92L, 92L, 91L, 91L, 91L, 91L, 90L, 90L, 91L),
  Speed = c(7.3, 7.4, 7.3, 7.4, 7.3, 7.3, 7.2, 7.1, 6.9, 6.7)),
  .Names = c("Date", "Direction", "Speed"),
  row.names = c(NA, 10L),
  class = "data.frame")

Ответы [ 4 ]

0 голосов
/ 12 мая 2018

rollapplyr (r в конце означает выравнивание по правому краю) в зоопарке позволяет задавать смещения с помощью width = list(offset_vector), например:

transform(timeLine, avg = rollapplyr(Speed, list(seq(-50, 0, 10)), mean, fill = NA))
0 голосов
/ 10 мая 2018

Я хотел бы проверить пакет tibbletime - в частности, функция collapse_by() полезна.Следующее должно работать (было бы легче протестировать с большим количеством данных):

library(tidyverse)
library(lubridate)
library(tibbletime)

tbl_time(timeLine, index = Date) %>%
  filter(minute(Date) %in% seq(0, 50, 10)) %>%
  collapse_by("hour", clean = TRUE) %>%
  group_by(Date) %>%
  summarise_all(mean)

Примечание: В зависимости от того, как вы относитесь к своим часам, вы можете изменить строку collapse_by на collapse_by("hour", clean = TRUE, side = "start")- по умолчанию он будет использовать side = "end".

0 голосов
/ 10 мая 2018

Решение состоит в том, чтобы сначала фильтровать данные 0, 10, 20, 30, 40, 50th минут.Можно разделить minute даты / времени на 10 и проверить, чтобы remainder было равно 0, чтобы отфильтровать данные для данных 0, 10, 20, 30, 40, 50th минут.Примените zoo::rollmean для каждых 6 наблюдений.Таким образом, среднее значение для каждого часа будет рассчитываться с использованием данных 10-й, 20-й, 30-й, 40-й, 50-й и 0-й минут.Наконец, выберите minute == 0 (в течение часа).

library(zoo)
library(lubridate)
library(tidyverse)

timeLine_mod %>% filter(minute(Date) %% 10 == 0) %>%
mutate(meanSpeed = rollmean(Speed, 6, fill = FALSE, align = "right")) %>%
filter(minute(Date) == 0)

#                  Date Direction Speed meanSpeed
# 1 2017-07-06 01:00:00        91   6.7       6.7
# 2 2017-07-06 02:00:00        91   6.7       6.7
# 3 2017-07-06 03:00:00        91   6.7       6.7

Данные: Поскольку OP предоставил данные только за 10 минут, что недостаточно для расчета среднечасового значения.Следовательно, я расширил данные, чтобы охватить 3 часа:

timeLine <- structure(list(Date = structure(c(1499270460, 1499270520, 1499270580, 
1499270640, 1499270700, 1499270760, 1499270820, 1499270880, 1499270940, 1499271000), 
class = c("POSIXct", "POSIXt"), tzone = "Asia/Hong_Kong"), 
Direction = c(93L, 92L, 92L, 91L, 91L, 91L, 91L, 90L, 90L, 91L), 
Speed = c(7.3, 7.4, 7.3, 7.4, 7.3, 7.3, 7.2, 7.1, 6.9, 6.7)), 
.Names = c("Date", "Direction", "Speed"), row.names = c(NA, 10L), 
class = "data.frame")

#Extend data to cover 3 hours as
timeLine_mod <- timeLine %>% complete(Date = seq(min(Date),
         min(Date)+60*60*3-60,by="1 min"))

#Repeat the value of Direction and Speed
timeLine_mod$Direction <- timeLine$Direction
timeLine_mod$Speed <- timeLine$Speed
0 голосов
/ 10 мая 2018

Хм, почти наверняка есть более элегантный способ, но я думаю, что это работает.Я использовал пакет lubridate для упрощения преобразования в формат даты и времени:

library(tidyverse)
library(lubridate)

df = read.csv(text="
              Date,Time,Direction,Speed
              2001-07-04,09:01:00,310,4.0
              2001-07-04,09:02:00,310,3.9
              2001-07-04,09:03:00,310,3.9
              2001-07-04,09:04:00,310,3.9
              2001-07-04,09:05:00,300,3.9
              2001-07-04,09:06:00,300,4.0
              2001-07-04,09:07:00,300,3.9
              2001-07-04,09:08:00,300,4.0
              2001-07-04,09:09:00,300,4.0
              2001-07-04,09:10:00,300,4.0
              2001-07-04,09:11:00,290,4.0
              2001-07-04,09:12:00,290,4.0
              2001-07-04,09:13:00,290,4.0
              2001-07-04,09:14:00,290,4.0
              2001-07-04,09:15:00,290,4.0", sep=",", header = TRUE, row.names = NULL)

lagged_avg = function(col) {
  lag_positions = c(0,10,20,30,40,50)
  sum = 0
  for (n in lag_positions) {
    sum = sum + lag(col, n)
  }
  return(sum/6)
}

df = df %>%
  mutate(datetime = ymd_hms(paste0(Date," ",Time))) %>%
  mutate(lag = lagged_avg(Speed)) %>%
  select(-Date, -Time)
...