Условная накопительная сумма с динамическим условием - PullRequest
1 голос
/ 31 марта 2019

Добрый день, я пытаюсь создать накапливающееся среднее значение с "поворотом" - я хочу только усреднить поля, которые датированы до текущего (могут быть поля с той же датой)

мне удалосьделать это «грязным путем», используя несколько пользовательских функций, но это занимает слишком много времени, и это очень неэффективно - я уверен, что есть лучший способ.

Я думал о чем-то вроде:

averages <- DB %>% group_by(field1,field2) %>% mutate(Avg=cummean(???*value1)))

как получить доступ к текущему наблюдению для функции cummean

, по которому я пошел, чтобы создать логический вектор для каждого подмножества с циклом

for (i in 1:length(datevector)-1)
    logicalvector[i] <- datevector[length(datevector)]>datevector[i]
  logicalvector[length(datevector)]=F

и использовать это в другой функции для вычисления среднего значения

. Простой пример:

df <- data.frame(id=1:5,Date=as.Date(c("2013-08-02","2013-08-02","2013-08-03","2013-08-03","2013-08-04")),Value=c(1,4,5,2,4))

id  Date    Value     accum mean
1  02/08/2013     1         0
2  02/08/2013     4         0
3  03/08/2013     5        2.5
4  03/08/2013     2        2.5
5  04/08/2013     4         3

Explanation:
there are no observation with a prior date for the first 2 observations so the mean is 0
the 3rd observation averages the 1st and 2nd, so does the 4th.
the 5th observation averages all

Ответы [ 2 ]

2 голосов
/ 31 марта 2019

Это может быть реализовано как сложное самостоятельное соединение в SQL. Это присоединяет к каждой строке все строки с меньшим значением Date amd для каждой строки, в среднем Value в соединенных строках. coalesce используется для присвоения 0 в ситуации, когда в противном случае среднее значение будет равно нулю.

library(sqldf)

sqldf("select a.*, coalesce(avg(b.Value), 0) as mean
  from df as a 
  left join df as b on b.Date < a.Date
  group by a.rowid")

дает:

  id       Date Value mean
1  1 2013-08-02     1  0.0
2  2 2013-08-02     4  0.0
3  3 2013-08-03     5  2.5
4  4 2013-08-03     2  2.5
5  5 2013-08-04     4  3.0
1 голос
/ 31 марта 2019

Используя data.table и lubridate, у вас есть эта опция:

library(data.table)
library(lubridate)
dt <- data.table(id=c(1:5))
dt$Date <- c("02/08/2013", "02/08/2013", "03/08/2013", "03/08/2013", "04/08/2013")
dt$Value <- c(1,4,5,2,4)
dt$Date <- dmy(dt$Date)

cummean <- function(d){
  if(nrow(dt[Date<d])>0)
    dt[Date<d, sum(Value)/.N]
  else 0
}

dt[, accuMean:=mapply(cummean,Date)]

#    id    Date    Value accuMean
#1:  1 2013-08-02     1      0.0
#2:  2 2013-08-02     4      0.0
#3:  3 2013-08-03     5      2.5
#4:  4 2013-08-03     2      2.5
#5:  5 2013-08-04     4      3.0

Решение, когда у вас есть несколько значений:

library(data.table)
library(lubridate)
dt <- data.table(id=c(1:5))
dt$Date <- c("02/08/2013", "02/08/2013", "03/08/2013", "03/08/2013", "04/08/2013")
dt$Value_1 <- c(1,4,5,2,4)
dt$Value_2 <- c(3,2,0,1,2)
dt$Value_3 <- c(4,9,3,3,3)
dt$Date <- dmy(dt$Date)

cummean <- function(d,Value){
  if(nrow(dt[Date<d])>0)
    sum(dt[Date<d, Value, with=F])/dt[Date<d, .N]
  else 0
}

n <- 3
accuMean <- paste0("accuMean_", (1:n))
for(i in 1:n){
  print(i)
  dt[, (accuMean[i]):=mapply(cummean,Date,MoreArgs = list(paste0("Value_",i)))]
}

Предположим, у вас есть n значений с именем Value_i.Десять в вашем случае, вам нужно только установить n = 10

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...