使用需要并行写入数据帧的parSapply

时间:2018-08-18 13:23:07

标签: r parallel-processing time-series sapply

我有一个自定义函数,该函数遍历时间序列数据帧,并从原始时间序列返回30分钟的滑动窗口。从这30分钟开始,该函数将开始和结束时间戳记以及此滑动窗口的最小值和最大值写入另一个数据帧。

使用该sapply语句使该函数在整个数据范围内递归。

appapply速度太慢,但是可以工作。我希望能够并行化sapply,但是这样做时,代码将返回错误。我将此归因于将函数的最终结果并行写入同一数据帧的要求。

result_df_2 <- data.frame(Start.time=as.POSIXct(character()), finish.time = as.POSIXct(character()), max.value = double(), min.value = double(), stringsAsFactors = FALSE)

sliding_window <- function(sequence, time_row, Query, window_width) {
    sliding_window_1 <- Query[time_row <= (time_row[sequence] + window_width * 60 + 1 * 60) & 
                              time_row > time_row[sequence], ]
    if (nrow(sliding_window_1) >= 1) {
        temp.df <- data.frame(Start.time = sliding_window_1$TIME[1],
                              finish.time = sliding_window_1$TIME[nrow(sliding_window_1)],
                              max.value = max(sliding_window_1$C19.X.AAA.01, na.rm = T),
                              min.value = min(sliding_window_1$C19.X.AAA.01, na.rm = T))
        result_df_2[nrow(result_df_2)+1,] <<- temp.df[1,]
    }
}

sapply(1:(nrow(WBP) - 30), FUN = sliding_window, Query = WBP, time_row = WBP$TIME, window_width = 30)

在这个问题Parallel while loop in R中提到这样一种情况的答案可能是并行的。我需要您的帮助才能知道如何。

下面是dput(WBP [1:10,])的输出

structure(list(TIME = structure(c(1484589600, 1484589660, 1484589720, 
                              1484589780, 1484589840, 1484589900, 1484589960, 1484590020, 1484590080, 
                              1484590140), class = c("POSIXct", "POSIXt"), tzone = ""), C19.X = c(216.193, 
                                                                                                  220.204, 218.845, 218.676, 219.194, 219.976, 219.894, 219.168, 
                                                                                                  216.713, 216.551), C19.N = c(214.201, 216.985, 218.15, 217.3, 
                                                                                                                               218.11, 218.194, 218.332, 216.679, 215.343, 215.403), C19.X.AA.01 = c(216.193, 
                                                                                                                                                                                                     220.204, NA, NA, NA, NA, NA, NA, NA, 216.551), C19.X.AAA.01 = c(216.193, 
                                                                                                                                                                                                                                                                     220.204, 219.747375, 219.29075, 218.834125, 218.3775, 217.920875, 
                                                                                                                                                                                                                                                                     217.46425, 217.007625, 216.551)), .Names = c("TIME", "C19.X", 
                                                                                                                                                                                                                                                                                                                  "C19.N", "C19.X.AA.01", "C19.X.AAA.01"), row.names = c(NA, 10L
                                                                                                                                                                                                                                                                                                                  ), class = c("data.table", "data.frame"))

1 个答案:

答案 0 :(得分:0)

提示1:使用无副作用的“纯”功能

在您的示例中,您初始化return_df_2并使用该函数对其进行了更改。这并不是出于sapply之类的目的而创建的(这是并行性不好的一个原因)。相反,尝试使函数返回所需的结果,然后将所有答案放在data.frame中。例如,

f <- function(x) {
  x / 10 # this returns a value instead of modifying something that already exists
}
result <- sapply(1:5, FUN = f)
data.frame(result)
##   result
## 1    0.1
## 2    0.2
## 3    0.3
## 4    0.4
## 5    0.5

提示2:并行化可能很困难

因为子进程并不总是可以访问父进程中定义的内容。在这种情况下,您会得到'result_df_2' not found,因为孩子们没有通过。您可以使用上述策略来跳过该错误(但是,如果您拥有更复杂的功能,那么将来无论如何您都可能会遇到该问题,所以仅供参考)。这是一个使用parSapply的简单示例:

library(parallel)
cl <- makeCluster(2)
result <- parSapply(cl, 1:5, f)
stopCluster(cl)

data.frame(result)
##   result
## 1    0.1
## 2    0.2
## 3    0.3
## 4    0.4
## 5    0.5

为您提供可能的解决方案(但是如果没有真实数据很难说)

让函数返回temp.df而不是修改data.frame,然后使用dplyr::bind_rows或类似方法将返回的数据帧列表转换为一个单个数据帧(或者,您希望解决方案看)。

sliding_window <- function(sequence, time_row, Query, window_width) {
  sliding_window_1 <- Query[time_row <= (time_row[sequence] + window_width * 60 + 1 * 60) & 
                              time_row > time_row[sequence], ]
  if (nrow(sliding_window_1) >= 1) {
    temp.df <- data.frame(Start.time = sliding_window_1$TIME[1],
                          finish.time = sliding_window_1$TIME[nrow(sliding_window_1)],
                          max.value = max(sliding_window_1$C19.X.AAA.01, na.rm = T),
                          min.value = min(sliding_window_1$C19.X.AAA.01, na.rm = T))
  }
  else {
    temp.df <- data.frame(Start.time=as.POSIXct(character()), finish.time = as.POSIXct(character()), max.value = double(), min.value = double(), stringsAsFactors = FALSE)
  }
  temp.df
}

好吧,去吧。祝你好运,飞速前进。