#r #dplyr #moving-average
#r #dplyr #скользящее среднее
Вопрос:
У меня есть набор данных, который может содержать НЕСКОЛЬКО наблюдений за дату. Таким образом, может быть 5 наблюдений на date1, 2 наблюдения на date2 и 1 наблюдение в group3.
Я хочу рассчитать скользящее среднее — по дате — и, что важно, не суммируя / не уменьшая количество строк. То есть в приведенном выше примере у меня все равно было бы 8 строк данных, а в столбце рядом с ним у меня была бы скользящая средняя цена на эту дату. Я нахожу это сложным, потому что, когда я использую типичную скользящую функцию из ZOO package, она выполняется построчно, и я не знаю, как получитьэто пропустить по ДАТЕ
например, первым шагом обычно было бы:
df %>%
groupy_by(DATE) %>%
summarise(mean_daily_price = mean(price)) %>%
ungroup() %>%
arrange(Date) %>%
mutate( ra = rollapply(price, 2, mean, partial=T)
— но подведение итогов заставляет меня терять строки.
library(dplyr)
library(zoo)
DF = structure(list(Date = c("Jan-13", "Jan-13", "Jan-13", "Jan-13", "Jan-13", "Jul-14", "Jul-14", "Oct-16"), Price = c(100L, 200L, 300L, 1000L, 400L, 150L, 50L, 600L), Average.by.Date = c(400L, 400L, 400L, 400L, 400L, 100L, 100L, 600L), Moving_Average_Size_2 = c(NA, NA, NA, NA, NA, 250L, 250L, 350L)), .Names = c("Date", "Price", "Average.by.Date", "Moving_Average_Size_2"), class = "data.frame", row.names = c(NA,
-8L))
Комментарии:
1. Ваш вопрос немного неясен. Каков ваш ожидаемый результат? Что вы подразумеваете под «пропуском по дате»?
2. Пожалуйста, убедитесь, что имена переменных в вашем коде совпадают с именами переменных в вашем фрейме данных и что в вашем коде нет других опечаток.
Ответ №1:
В приведенном ниже коде мы используем mutate
вместо summarise
добавить mean_daily_price
, чтобы сохранить все строки фрейма данных. Затем в финале mutate
мы работаем rollapply
только с уникальными значениями mean_daily_price
, но затем используем table
и rep
повторяем вывод rollapply
по количеству строк для каждого Date
.
DF %>%
arrange(Date) %>%
group_by(Date) %>%
mutate(mean_daily_price = mean(Price)) %>%
ungroup() %>%
mutate(ra = rep(rollapply(unique(mean_daily_price), 2, mean, fill=NA, align="right"),
table(Date)[order(unique(Date))]))
Date Price Average.by.Date Moving_Average_Size_2 mean_daily_price ra 1 Jan-13 100 400 NA 400 NA 2 Jan-13 200 400 NA 400 NA 3 Jan-13 300 400 NA 400 NA 4 Jan-13 1000 400 NA 400 NA 5 Jan-13 400 400 NA 400 NA 6 Jul-14 150 100 250 100 250 7 Jul-14 50 100 250 100 250 8 Oct-16 600 600 350 600 350
Комментарии:
1. Извините, но это неправильно. Здесь правильным ответом является MOVING_AVERAGE_SIZE_2 (или НУЛИ могут быть = 400) — здесь это менее важно, поскольку на данный момент только 1 дата наблюдения. Кроме того, возможно, я что-то упускаю, но уникальное (mean_daily_prrice) — что, если у меня одинаковая средняя цена на несколько дат?
Ответ №2:
Я думаю, что ваш самый безопасный подход должен быть двухэтапным процессом — вычислите скользящие средние Date
, а затем объедините их обратно (все еще используя dplyr
здесь)
rolledAvg <-
DF %>%
group_by(Date) %>%
summarise(mean_daily_price = mean(Price)) %>%
ungroup() %>%
arrange(Date) %>%
mutate( ra = rollapply(mean_daily_price
, 2
, mean
, partial=T
, fill = NA))
left_join(DF, rolledAvg)
дает:
Date Price Average.by.Date Moving_Average_Size_2 mean_daily_price ra
1 Jan-13 100 400 NA 400 250
2 Jan-13 200 400 NA 400 250
3 Jan-13 300 400 NA 400 250
4 Jan-13 1000 400 NA 400 250
5 Jan-13 400 400 NA 400 250
6 Jul-14 150 100 250 100 350
7 Jul-14 50 100 250 100 350
8 Oct-16 600 600 350 600 600
Я вижу в комментарии к другому ответу, что вы не считаете, что первое ra
должно быть 250 — если это так, измените расчет в своем вызове на rollapply
. Прямо сейчас, похоже, он ведет себя так, как ожидалось / задокументировано. Итак, если вы хотите что-то другое, вам нужно будет объяснить желаемое изменение (возможно, отдельный вопрос).
Еще одно предостережение, особенно важное для любых других читателей, которые наткнутся на это: этот текущий подход рассматривает последовательные записи даты как равноудаленные, независимо от того, насколько далеко они на самом деле находятся. Если это подходит для ваших нужд, отлично. Но во многих случаях вам может потребоваться позаботиться о фактическом промежутке времени между измерениями.
Аналогично, текущий подход теряет всю информацию о количестве проведенных измерений, возможно, стоит рассмотреть подход, который взвешивается по количеству наблюдений (если вы не доверяете вычисленному среднему значению за каждый день).
Комментарии:
1. Вместо отдельного
left_join
, вы также можете добавитьright_join(DF)
в цепочку.2. Попробуйте
rollapplyr
вместоrollapply
. Также, если левое соединение записывается какleft_join(x = DF)
, тогда оно может быть добавлено в конце конвейера.3. Оба @eipi10 и @G Grothendieck правы в том, что вызов (или
left_join
илиright_join
) может быть добавлен в конце конвейера / цепочки. Я оставил их разделенными здесь, чтобы подчеркнуть, что*_join
это была уникальная часть ответа (и что конструкция в вопросе может быть понята как правильная , только первый шаг).