优化 R 中的时间序列聚合

Posted

技术标签:

【中文标题】优化 R 中的时间序列聚合【英文标题】:Optimize time series aggregation in R 【发布时间】:2022-01-19 12:25:20 【问题描述】:

我有很大的时间序列(日期时间、值、实例),在可视化之前,我需要使用每个实例的每个时间间隔的最大值(在我的示例中为 15 分钟)聚合数据。

我没有在 R 中找到原生聚合函数,所以我使用 celling_data 和 cut 方法创建了 2 个自定义函数。看我的例子:

library(tidyverse)
library(lubridate)


agg_fun_1 <- function (data, aggregation_period = 900) 

agg_period <- paste(aggregation_period, "secs")

agg_data <- data %>%  
    group_by(across(-c(Value, datetime)),  
             datetime = as.POSIXct(cut(datetime, agg_period)) + aggregation_period) %>%
    summarise (Value = max(Value) , .groups = "drop") %>% 
    mutate(Value = ifelse(is.infinite(Value), NA, Value))

return (agg_data)




agg_fun_2 <- function (data, aggregation_period = "15 mins") 

    agg_data <- data %>% 
        group_by(across(-c(Value, datetime)), datetime = ceiling_date (datetime, aggregation_period))
    
    suppressWarnings(
        agg_data <- agg_data %>% 
            summarise(Value = max(Value,  na.rm = F), .groups = "drop") %>% 
            mutate(Value = ifelse(is.infinite(Value), NA, Value))
    )   
    
    return (agg_data)
    



set.seed(42)

example_data <- tibble()

for(i in 1:256) 
    
    example_data <- rbind(example_data,
        
        data.frame( Instance = rep(i,20002),
                     datetime = seq.POSIXt(as.POSIXct("2020-12-26 10:00:00"), as.POSIXct("2020-12-26 10:00:00") + 15*20001, "15 sec"),
                     Value = sample(0:1000, 20002, replace=TRUE)
                     )   
    )
    


gc()

start_time <- Sys.time()

agg_fun_1(example_data)

end_time <- Sys.time()
end_time - start_time

gc()

start_time <- Sys.time()

agg_fun_2(example_data)

end_time <- Sys.time()
end_time - start_time
agg_fun_1 执行时间为 2.3 分钟,RAM 使用量 - 在我的笔记本电脑上约为 +702 MB。 agg_fun_2 执行时间为 1.9 分钟,RAM 使用量 - 在我的笔记本电脑上约为 +930 MB。

在真实环境中,我将并行运行 8 个 R 脚本,我的数据可能比我使用的数据大 3-5 倍。在这种情况下,我可能会面临资源不足的情况。

有什么方法可以优化我的函数的 RAM 使用和执行时间,或者有更好的聚合函数吗?

【问题讨论】:

【参考方案1】:

大部分时间都花在计算您的汇总时间(cut 或 ceiling_date)上。尝试在没有其他代码的情况下计算它以查看它。

使用 datetime 作为秒数直接计算,因为 origin 速度更快(特别是如果您的 agg_period 可以很容易地以秒数给出)

这里使用 data.table 而不是 tidyverse(但应该对 tidy 做同样的事情)。

# data.frame on steroids
library(data.table)

# transform you data as data.table
example_data <- setDT(example_data)

agg_period <- 15*60 # seconds

agg_data <- example_data[, 
  # group by aggregated datetime
  by=as_datetime(floor(as.integer(datetime)/agg_period)*agg_period),
  # compute Value as max Value of group
  .(Value=max(Value))
]

# replace infinite Value with NA (:= means inplace)
agg_data[is.infinite(Value), Value:=NA]

【讨论】:

您确定此代码有效吗?我看到一个错误:[.data.frame(example_data, , by = as_datetime(floor(as.integer(datetime)/agg_period) * 中的错误:未使用的参数 (by = as_datetime(floor(as.integer(datetime)/agg_period) * agg_period)) 您需要按照说明使用包 data.table。我修改我的答案以使其清楚

以上是关于优化 R 中的时间序列聚合的主要内容,如果未能解决你的问题,请参考以下文章

对数据帧字典执行操作的优化方式 w.r.t.聚合数据框

在 R 中的聚合中命名列

如何根据 R 中的日期聚合数据?

R中的聚合平均值

R中的聚合函数同时使用两列

在R中的data.frame中聚合一个轴[重复]