使用dplyr对函数内的时间序列数据进行分组和汇总

时间:2019-06-07 04:59:27

标签: r function dplyr time-series

提前感谢您的帮助。我知道也有类似的问题,但是它们都比这里要问的问题简单,因为它们按因子而不是DateTime处理分组。

我的目标是编写一个可以应用于海洋数据集中各种物理参数(<100列)的函数。每个物理参数每隔30分钟自动记录一次,并且需要进行相同的复杂摘要计算。

数据帧(df)如下:

dt                  par 1    par 2   par 3    par 100
2018-06-06 00:00    95.6      976    0.18     ...
2018-06-06 00:30    NA       1002    0.19     ...
2018-06-06 01:00    95.9     1019    0.20     ...
...
[regularly spaced data]
...
2018-10-31 23:00    72.4     887     NA       ...
2018-10-31 23:30    72.1     889     0.17     ...

我有代码可以成功地为数据框的单个参数(1列)进行所需的计算。要将这些计算应用于其他参数,需要复制和粘贴代码,然后在该复制和粘贴的代码中更改列名。似乎有一种更好的方法可以做到这一点,例如编写一个函数(我曾尝试做)或使用data.frame(我正试图做得更好,但实际上不知道那是否可行)。我试图写一个函数。

fun = function(df,dt, par){
df1=df %>% #new dataframe to temporarily store site specific calculations
  group_by(hour = cut(dt , breaks="60 min")) %>% #Cut data into 1-hour intervals
  summarize(x = mean(par)) #Calulated the average for each 1-hour interval 
df1$hour <- as.Date(df1$hour) #Remove time element from datetime so hourly averaged can be grouped by date
df.avg <- aggregate(df1$x, by=list(df1$hour), mean) #calculate daily average 
df.max <- aggregate(df1$x, by=list(df1$hour), max)  #calculate daily max 

#Temporary dataframe
date=as.data.frame(df.avg$Group.1) #used to calculate 7-day rolling mean
avg=as.data.frame(df.avg$x) #used to calculate 7-day rolling mean
max=as.data.frame(df.max$x) #used to calculate 7-day rolling mean

#7-day rolling mean (centered) of average daily mean temp
calc.avg=as.data.frame(cbind(date, (rollapply(avg,7,mean,align='center',fill=NA)))) 
#7-day rolling mean (centered) of average daily maximum temp
calc.max=as.data.frame(cbind(date, (rollapply(max,7,mean,align='center',fill=NA))))

#Identify maximum temperatures and date of occurence based on the 7-day running mean  calculation
df.avg=calc.avg[which.max(calc.avg$`df.avg$x`),]
df.max=calc.max[which.max(calc.max$`df.max$x`),]

#site-specific data as dataframe to be combined with all sites at end
calc=cbind(df.avg, df.max)
names(calc)=c("Date AVG", "Par AVG", "Date MAX", "Par Max")
nam=data.frame("Par 1 Summary")#                                                      
names(nam)="Location"
output=cbind(nam,calc) 
output}

par=df$Par1

fun(df,dt,par)

这不起作用,我收到一条错误消息“参数不是数字或逻辑”。但是,如果在函数的摘要行中将文本par替换为Par 1,则获得所需的输出。我认为可能存在一个与语法有关的问题,我没有坚持,但是无法弄清它是什么。

我最终希望获得的结果是一个包含以下信息的数据框:

Parameter    Date of AVG    AVG     Date of MAX    MAX
Par 1        2018-07-21     99.9    2018-07-25     101.1
Par 2        2018-07-03     1005    2018-07-25     1081
Par 3        2018-07-20     0.29    2018-07-27     0.45
...
[Par 4 - 99]
...
Par 100      ...            ...     ...            ...

1 个答案:

答案 0 :(得分:0)

首先,在查看数据时,第dt列看起来不是日期时间格式。使用POSIXct之前,您需要转换成cut类。您可以将函数的初始部分更改为

library(dplyr)
library(rlang)

df1 = df %>% group_by(new = cut(as.POSIXct(dt),
            format = "%Y-%m-%d %H:%M", breaks="60 min")) %>%
            summarize(x = mean(!!sym(par), na.rm = TRUE))

如果代码的其余部分正确,则应给出预期结果,因为它将文字字符串转换为符号,然后对其求值。而且据我所知,该功能仅适用于一列。尝试将其作为

用于第一列
fun(df, dt, "par1")

,然后检查您是否获得了预期的输出。现在,您需要对所有可以使用paste0生成并使用lapply / map

应用的100列进行此操作
lapply(paste0("par ", 1:100), function(par) fun(df,dt,par))

这将为您生成一个数据帧列表,您可以将其与do.call绑定在一起

do.call(rbind, lapply(paste0("par ", 1:100), function(par) fun(df,dt,par)))