我想计算多维数组的三维平均值。由于这个维度应该是时间,我想计算月度均值。为此,我尝试使用apply,但我不确定问题出在哪里。让我们说我的数据如下:
#Creating a sample
m <-array(1:12, dim=c(20,4,36))
#number of months
months <- seq(1:12)
#Compute the mean over each month (dimension of the result should be [20,4,12]
monmean <- apply(m,1:2,function(x) for(i in 1:12) mean(x[,,months==i],na.rm=TRUE))
任何想法? 提前致谢
答案 0 :(得分:0)
我想我明白你在追求什么。这实际上比看起来要复杂得多,因为几个月不是常规的时间段;它们的天数各不相同,而且由于闰年,2月份的年份不同。因此,简单的常规逻辑或数字索引向量将不足以精确地计算该结果。您需要考虑数组z维度所涵盖的确切日期。
您可以做的是单独计算一个日期向量,该日期向量标识与数组的每个z-index对应的日期。在每个z行的apply()
调用中,您可以调用strftime()
来提取每个这样的日期的月份,并使用tapply()
按月分组每月{{3} }}秒。以下是它的完成方式:
set.seed(1);
R <- 48;
C <- 39;
Z <- 3653;
N <- R*C*Z;
a1 <- array(rnorm(N,10,2),c(R,C,Z));
dates <- seq(as.Date('2000-01-01'),as.Date('2009-12-31'),1);
a2 <- aperm(apply(a1,1:2,function(x) tapply(x,strftime(dates,'%m'),mean)),c(2,3,1));
这是一个演示,展示了一些正确的具体证明:
for (r in sample(1:nrow(a2),2)) for (c in sample(1:ncol(a2),2)) for (m in sample(1:dim(a2)[3],2)) cat(sprintf('[%02d,%02d,%3s] %f %f\n',r,c,month.abb[m],mean(a1[r,c,strftime(dates,'%m')==sprintf('%02d',m)]),a2[r,c,m]));
## [14,05,Aug] 10.030313 10.030313
## [14,05,Apr] 10.200982 10.200982
## [14,25,Jan] 9.957879 9.957879
## [14,25,Apr] 10.185447 10.185447
## [26,34,Oct] 10.056931 10.056931
## [26,34,Nov] 9.876327 9.876327
## [26,17,Apr] 10.005423 10.005423
## [26,17,Sep] 10.009785 10.009785
备注强>
apply()
作为边距调用1:2
,您走在正确的轨道上,因为这样您就可以在每个z线上独立操作,这样您就可以对其进行分组按月划分z线,计算沿z线每个月的平均值。apply()
有一种令人烦恼的习惯,即以不同于人们通常预期的不同换位方式返回结果。对于二维用法,通常只需调用mean()
即可解决此问题,但由于我们在此处处于三个维度,因此我们需要调用t()
来修复维度顺序。a2
中的z-index 1:12对应于Jan-Dec的月份。如果您的日期不是从1月开始,那么此解决方案仍然有效,但您必须注意z-index与结果中的月份之间的对应关系。例如,我的“正确性证明”代码假设索引1:12对应于Jan-Dec月份,但如果输入数组中的月份以不同的顺序发生则不正确。在写这个答案的时候,我实际上认为有点不同,而且可以提出稍微好一点的解决方案。您可以只调用tapply()
一次,按行,然后按列分组,最后按月分组。不幸的是,tapply()
似乎并不是设计为自然循环其组向量以覆盖输入向量,因此我们必须使用精心设计的aperm()
调用来自行循环(使用each
}和times
参数都很仔细 - 我想tapply()
实际上甚至不知道如何正确地为我们的输入数据做这些),但除此之外,它是相当简单的:
a3 <- tapply(a1,list(rep(1:R,C*Z),rep(1:C,each=R,times=Z),rep(strftime(dates,'%m'),each=R*C)),mean);
以下是一个证据,证明结果与我的第一个方法相同(rep()
必须先修复才能使dimnames()
调用起作用,但这很简单):
dimnames(a3) <- dimnames(a2);
identical(a3,a2);
## [1] TRUE
以下是使用identical()
进行的一些基本性能测试,以了解第二种解决方案的优越性:
first <- function() a2 <- aperm(apply(a1,1:2,function(x) tapply(x,strftime(dates,'%m'),mean)),c(2,3,1));
second <- function() a3 <- tapply(a1,list(rep(1:R,C*Z),rep(1:C,each=R,times=Z),rep(strftime(dates,'%m'),each=R*C)),mean);
system.time({ first() });
## user system elapsed
## 3.672 0.015 3.719
system.time({ first() });
## user system elapsed
## 3.672 0.016 3.720
system.time({ second() });
## user system elapsed
## 1.797 0.344 2.135
system.time({ second() });
## user system elapsed
## 1.719 0.391 2.124