【问题标题】:How to calculate maximum 8-h moving (rolling) averages in R?如何计算 R 中的最大 8 小时移动(滚动)平均值?
【发布时间】:2018-11-14 08:29:02
【问题描述】:

我正在使用 R。 我知道计算移动平均线是一个在这个网站上有几个答案的主题,但我有一些问题让我的问题与众不同。

我有一个数据框,其中包含 8784 小时(366 天 * 24 小时)的空气污染物(臭氧)浓度。此数据框包含一些 NaN 值(缺失值)。 该过程包含以下步骤:

1- 计算每小时浓度的 8 小时移动(滚动)平均值:即每 8 个浓度应以这种方式平均:1 到 8 的平均值,2 到 9 的平均值,3 到 10 的平均值等。 这导致每天(每 24 小时)获得 24 个移动平均线。

2- 对于每一天,我想要最大的 8 小时移动平均线:即在 24 条移动平均线中,应该选择最大的数字。最后,将选择 366 条移动平均线(366 天)。

3- 应创建一个包含 366 条移动平均线的新数据框。

我知道有一些包(openair、zoo、TTR)可以做这样的事情,但是有没有什么方法可以在没有任何包的情况下编写代码?

An Exmaple of my data 

     ColName
1    18.76 
2    12.92 
3    8.12 
4    NaN 
5    12.92 
6    3.77 
7    18.76 
8    9.52 
9    94.09 
10    18.76 
11    14.13 
12    8.12 
13    2.04 
14    12.92 
15    9.17 
.
.
.
8783    34.58
8784    64.23 

主数据框的名称是“Hourly”。我试过这些代码:

Hourly1 <- c(0, cumsum(ifelse(is.nan(Hourly), 0, Hourly))) 
rsum <- (Hourly1[(Hourly1+1):length(Hourly1)] - Hourly1[1:(length(Hourly1) - 8)]) / 8

但是当我尝试第一行时,出现以下错误:

Error in is.nan(Hourly) : default method not implemented for type 'list'

更新: 我使用了以下代码,但没有正确计算出 8 小时平均值的最大值:

Hourly2<-as.numeric(Hourly$Average)

names(Hourly2) <- rep(seq.Date(as.Date("2017-01-01"), by=1, length.out=366), each=24)

x<-Hourly2
#use cumsum to get the moving average, keep NaNs
cx <- c(0, cumsum(ifelse(is.nan(x), 0, x))) + c(0,x)*0

n <- 8

rsum <- (cx[(n+1):length(cx)] - cx[1:(length(cx) - n)]) / n

res <- data.frame(mov_avg=rsum, days=names(rsum))


#select max from each day, ignoring NaN's
mx <- aggregate(mov_avg~days, data=res, max)

我将最终结果(最多 366 个 8 小时平均值,每年 1 天)与一个标准的预先批准的数据集进行了比较。在某些日子里,代码计算的平均值是正确的,但在其他日子里却不是!我没明白它的逻辑。

你可以找到我的原始数据集here!

更新 2:

Here is a link to download不同方法产生的最终结果!

更新3:

结果之间的差异是由于计算移动平均线的方法不同。计算移动平均线的方法有左、右、中三种。这里大伙提出的代码遵循“正确”的方法。

【问题讨论】:

  • 有一个答案here 在base 中使用cumsum
  • @Esther 我这样做了,但出现以下错误:错误:(列表)对象不能被强制输入'double'
  • 您能添加一小部分数据和您尝试过的代码吗?另外,您希望如何处理 NaN?例如,您想排除它们并在它们出现时取 7 个值的平均值吗?还是不使用 NaN 周围的时间段?
  • @Esther 我更新了这个问题。请参阅数据框示例和我尝试过的代码。我希望排除缺失值,但要计算该 8 小时部分的平均值。
  • 你在寻找函数rollapply? 即滚动手段:zoo::rollapply(1:10,2,means) 这找到手段 width=2

标签: r ozone


【解决方案1】:

下面是一个示例,说明如何在缺少值时使用 cumsum 执行此操作。我会仔细考虑它们在您的数据中的分布方式以及您希望如何处理它们。

#create some sample data
set.seed(1)
x <- rnorm(24*366)
names(x) <- rep(seq.Date(as.Date("2017-01-01"), by=1, length.out=366), each=24)
x[sample(100, 1:length(x))] <- NaN #add some missing values

#use cumsum to get the moving average, keep NaNs
cx <- c(0, cumsum(ifelse(is.nan(x), 0, x))) + c(0,x)*0

n <- 8

rsum <- (cx[(n+1):length(cx)] - cx[1:(length(cx) - n)]) / n

res <- data.frame(mov_avg=rsum, days=names(rsum))

#select max from each day, ignoring NaN's
mx <- aggregate(mov_avg~days, data=res, max)

days   mov_avg
1 2017-01-01 0.6404849
2 2017-01-02 0.3456389
3 2017-01-03 0.5998888
4 2017-01-04 0.6635502
5 2017-01-05 0.7244289
6 2017-01-06 0.1715349

【讨论】:

  • 当我使用这个代码时:Hourly1
  • "Hourly" 必须是测量的单个向量。您需要使用Hourly$ColName 之类的内容对其进行索引
  • 它计算了 8 小时滚动平均值中的 8777 个。但是当我运行代码 (res
  • 这是因为您的向量没有像示例中那样与之关联的名称。为了获得每日最大值,您可以通过某种方式告诉函数哪些值与哪些天对应。
  • 我运行代码成功,但是有问题。当我用 Excel 中相同数据集的输出检查最终结果时,我意识到代码的数学有错误。我确定Excel中的那个公式,你能再检查一下代码吗?计算 8 小时平均值的部分是正确的。但是计算每天最多 8 小时平均值的部分会产生不同的数字。谢谢
【解决方案2】:

我一直在努力解决这个问题,并找到了使用 map2() 的解决方案

# create a day of ozone data  

o3day <- data.frame(o3hrly = runif(24, 0.04, 0.1))

# 8hr average function
avg_8hr <- function(.x, .y, o3) {
  # print(.x)
  # print(.y)
  # print(o3)
  o3 %>% slice(.x:.y) %>% summarize(o38hr = mean(o3hrly))
}

max(unlist(map2(.x = 1:17, .y = 8:24, .f = avg_8hr, o3 = o3day)))

【讨论】:

    猜你喜欢
    • 2018-06-29
    • 2013-12-24
    • 2021-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    • 2015-03-07
    相关资源
    最近更新 更多