Как в R векторизовать движущееся подмножество данных?

У меня есть цикл ниже, который назначает два новых столбца таблице данных, используя данные за последние 21 день с 10 выборками в день. Это работает, но очень неэффективно, и мне нужна помощь в векторизации движущегося подмножества. У меня есть ощущение, что здесь задействована функция «применить», но я не уверен, как работать с непостоянным подмножеством. Ниже мой цикл: я начинаю с присвоения нулей новым столбцам, потому что я считаю, что изменение значений на месте происходит быстрее, чем добавление новых значений на каждой итерации.

data$up <- 0
data$down <- 0

for (i in ((21*10)+1): nrow(data)) {
  sub <- subset(data, data$date[i-(21*10)] < data$date &  data$date < data$date[i])
  data$up[i] <- mean(sub$ratio) + 2.25*sd(sub$ratio)
  data$down[i] <- mean(sub$ratio) - 2.25*sd(sub$ratio)
}

И здесь - это образцы данных и мой ожидаемый результат. Спасибо вам за помощь!


r
person Anna    schedule 19.06.2017    source источник
comment
Есть только 10 точек данных в день?   -  person Pierre Lapointe    schedule 19.06.2017
comment
Да, всего 10 точек данных в день   -  person Anna    schedule 19.06.2017
comment
Пожалуйста, не публикуйте изображения, вместо этого используйте dput для отображения данных   -  person akrun    schedule 19.06.2017
comment
Привет, @akrun, я использовал dput () в моей урезанной таблице данных, и теперь у меня есть длинный список значений. Как лучше всего показать эти данные? Спасибо   -  person Anna    schedule 19.06.2017


Ответы (1)


* EDITED для желаемого результата, которого я изначально не видел.

По сути, я использую dplyr для создания столбцов скользящего среднего и SD, используя RcppRoll. Затем group by укажите дату и снова измените, чтобы сохранить только последнюю запись за день. Мы должны сделать это, чтобы убедиться, что SD рассчитывается правильно.

library(RcppRoll); library(dplyr)
data <- data.frame(date=rep(seq.Date(from=as.Date("2017-01-01"),to=as.Date("2017-05-01"),by="days"),each =10),
                   ratio=1:110,stringsAsFactors=FALSE)
data%>%
  mutate(up=roll_meanr(ratio,n=21*10)+2.25*roll_sdr(ratio,n=21*10),
         down=roll_meanr(ratio,n=21*10)-2.25*roll_sdr(ratio,n=21*10))%>%
  group_by(date)%>%
  mutate(up=last(up),down=last(down))

         date ratio       up      down
       <date> <int>    <dbl>     <dbl>
1  2017-04-30    96 121.9414 -15.70329
2  2017-04-30    97 121.9414 -15.70329
3  2017-04-30    98 121.9414 -15.70329
4  2017-04-30    99 121.9414 -15.70329
5  2017-04-30   100 121.9414 -15.70329
6  2017-05-01   101 126.7033 -10.94139
7  2017-05-01   102 126.7033 -10.94139
8  2017-05-01   103 126.7033 -10.94139
9  2017-05-01   104 126.7033 -10.94139
10 2017-05-01   105 126.7033 -10.94139
11 2017-05-01   106 126.7033 -10.94139
12 2017-05-01   107 126.7033 -10.94139
13 2017-05-01   108 126.7033 -10.94139
14 2017-05-01   109 126.7033 -10.94139
15 2017-05-01   110 126.7033 -10.94139

РЕДАКТИРОВАТЬ2. Если вы согласны с расчетом стандартного отклонения на основе среднего значения за день (вместо всех 210 значений), вы можете сделать следующее:

data%>%
  group_by(date)%>%
  summarise(mean_ratio=mean(ratio))%>%
  mutate(up=roll_meanr(mean_ratio,n=21)+2.25*roll_sdr(mean_ratio,n=21),
         down=roll_meanr(mean_ratio,n=21)-2.25*roll_sdr(mean_ratio,n=21))%>%
  left_join(data,.)

           date ratio mean_ratio       up      down
1196 2017-04-30    96       95.5 123.1605 -16.92239
1197 2017-04-30    97       95.5 123.1605 -16.92239
1198 2017-04-30    98       95.5 123.1605 -16.92239
1199 2017-04-30    99       95.5 123.1605 -16.92239
1200 2017-04-30   100       95.5 123.1605 -16.92239
1201 2017-05-01   101      105.5 127.9224 -12.16049
1202 2017-05-01   102      105.5 127.9224 -12.16049
1203 2017-05-01   103      105.5 127.9224 -12.16049
1204 2017-05-01   104      105.5 127.9224 -12.16049
1205 2017-05-01   105      105.5 127.9224 -12.16049
1206 2017-05-01   106      105.5 127.9224 -12.16049
1207 2017-05-01   107      105.5 127.9224 -12.16049
1208 2017-05-01   108      105.5 127.9224 -12.16049
1209 2017-05-01   109      105.5 127.9224 -12.16049
1210 2017-05-01   110      105.5 127.9224 -12.16049
person Pierre Lapointe    schedule 19.06.2017
comment
Большое спасибо @P Lapointe! Есть ли способ свернуть значения так, чтобы у меня было одно и то же значение на каждый день? Если я включу параметр = 90, это не даст мне желаемого результата. - person Anna; 19.06.2017
comment
@Anna Как я уже сказал, SD рассчитывается с использованием среднего значения всех наблюдений, вы не можете группировать по дням. Вот почему я использую mutate(up=last(up),down=last(down)) для изменения данных до последней точки данных. Я добавлю еще одно решение - среднесуточное значение SD (21 точка данных вместо 210). - person Pierre Lapointe; 19.06.2017
comment
Спасибо @P Lapointe. Я все еще немного смущен тем, что вы используете% ›%. Я набрал то, что вы написали, начиная с данных% ›% и далее, и получаю сообщение об ошибке: не удалось найти функцию%›%, даже после установки пакета magrittr - person Anna; 20.06.2017
comment
@Anna Вам необходимо установить эти два пакета: library(RcppRoll); library(dplyr)% ›% - это функция magrittr, которая является зависимостью от dplyr и будет установлена ​​dplyr. % ›% Называется оператором трубопровода. Результат одной строки передается в следующую. - person Pierre Lapointe; 20.06.2017
comment
@P Lapointe Я очень благодарен за вашу помощь и прошу прощения за все последующие вопросы! Когда я запускаю ваш код выше в редактировании 1, я вижу тот же фрейм данных в моей консоли, но фрейм данных в моей среде содержит только столбцы даты и соотношения. Не следует ли изменять напрямую мой объект? - person Anna; 20.06.2017
comment
@Anna С конвейерами (% ›%) вы должны назначить конвейер объекту. Первая строка должна выглядеть так: data <- data%>% Это перезапишет объект данных с вычисленным результатом. Вы также можете поместить результаты в новый объект: data2 <- data%>% - person Pierre Lapointe; 20.06.2017