我想累积一个长期(包括不同年份)每天都测量的变量。变量的累积应从一年中的固定日期开始(例如,2月1日,或者换句话说,每年的日数(doy)32-我以前在doys工作)。每年的累积金额应从这个固定的日期开始。
我尝试使用setDT(df)[, whatiwant := cumsum(variable), by = rleid(DOY >= 32)]
或rle(DOY >= 32)
,但他们都不考虑每年的头几天。
理论上,函数ave()
应该可以正常工作,但是我不知道如何在不同年份的doy之间创建一个标志变量(它通常仅创建第一个)。
df <- data.frame(Date = seq(as.Date("2010-01-01"), by = 1, len = 1000),
Year = format(seq(as.Date("2010-01-01"), by = 1, len = 1000), "%Y"),
DOY = format(seq(as.Date("2010-01-01"), by = 1, len = 1000), "%j"),
Variable = rnorm(1000, mean=10, sd=3))
让我们从功能接口开始,该接口是可以解决问题的功能列表以及它们的输入和输出。
函数reset_cum_sums
包含两个元素,一个向量和该向量的重置位置列表。 输出将是一个包含累积总和的向量,并且总和在向量的每个所需位置重新开始。一个例子应该使它更清楚:
在每个重置位置,累计和重置。因此,如果输入为1:10
,位置矢量为3 5 7
,则输出为
input: [1 2 3 4 5 6 7 8 9 10]
output: [1 3 3 7 5 11 7 15 24 34]
如果未给出位置,将产生与cumsum
相同的结果。
is_feb_1st
如果日期为2月1日,则返回TRUE
,否则为FALSE
。我将把它留给您练习。
功能接口使用原始函数which
,split
和lapply
,其原始文档仅供阅读。]]
现在,解决方案的轮廓可以写成:
restart_feb_first<-function(data.frame) { reset_cum_sums(data.frame$value, which(is_feb_first(data.frame$date)) }
如果您的数据中的二月初值出现在位置32,32 + 365,32 + 730,..,则将构成您的位置向量。好消息是您可以轻松容纳leap年。
唯一具有挑战性的部分是写reset_cum_sums
;在这里,我提供了一种方法,不一定是最有效的方法。该程序将向量分成多个块,每个块都从适当的位置开始(在您的情况下,二月初)。请注意,此示例不需要管道操作员。您可以改用传统的功能符号。
另外,我以这种方式编写函数来说明一些R概念,而不一定编写性能最高的代码。但是,如果要重写,则只需将您在此功能上的工作隔离开。
# # purpose: define a function that creates cumulative sums # of vectors, but which reset at each position given by # the vector `positions`, which can be null. # reset_sum # parameters for hypothetical example set.seed(18) values=runif(50) # cumulative sums reset at these positions. positions=c(3,13,23,33,43) # dependencies require(magrittr) # or tidyverse for pipe operator reset_sum = function(vector,positions) { k=length(vector) # cut the list into pieces splitter=cut(1:k,breaks=c(-Inf,positions,Inf),right = FALSE) pieces=split(vector,splitter) # do the cumsum of each piece, and then glue then back together pieces %>% lapply(cumsum) %>% unlist(use.names=FALSE) }
这里是该函数的调用方式
# examples reset_sum(values,positions) reset_sum(rep(1,50),positions)
我希望这可以指导您找到适合您需求的解决方案。关键概念是将其分解,直到找到一个根据R原语“易于”编写的函数。如果您需要
reset_cum_sums
超级高效,那么用C或data.table
编写应该相当容易,但是让我们再待一天。