R - 提高do.call / by功能的速度

时间:2015-11-19 14:17:35

标签: r functional-programming tapply do.call

我对* apply系列函数表现得相当不错,而且我最近学会了使用do.call("rbind", by(...作为tapply的包装器。我正在使用大型数据集(Compustat),我有一个函数(见下文),它生成一个新的滞后变量列,我稍后将其附加到主数据框df

我的问题是非常慢。我创建了大约24个滞后变量,并且此函数中的处理大约需要1.5小时,因为数据集中有350,000多个公司年度观察值。

任何人都可以帮助提高此功能的速度,而不会丢失我认为合适的方面:

#' lag vector of unknown size (for do.call-rbind-by: using datadate to track)

lag.vec <- function(x){
   x   <- x[order(x$datadate), ] # sort data into ascending by date

   var <- x[,2]  # the specific variable name in data.frame x hereby ignored
   var.name <- paste(names(x)[2], "lag", sep = '.')       # keep variable name

   if(length(var)>1){  # no lagging if single observation

      lagged   <- c(NA, var[1:(length(var)-1)])
      datelag  <- c(x$datadate[1], x$datadate[1:(length(x$datadate) - 1)])
      datediff <- x$datadate - datelag

      y <- data.frame(x$datadate, datediff,  lagged)  # join lagged variable and difference in YYYYMMDD data

      y$lagged[y$datediff >= 20000 & !is.na(y$datediff)] <- NA   # 2 or more full years difference

      y <- y[, c('x.datadate', 'lagged')]
      names(y)  <- c("datadate", var.name)

   } else {  y <- c(x$datadate[1], NA); names(y) <- c("datadate", var.name) }
   return(y)
}

然后我在一个命令中单独为每个要为其生成滞后系列的变量调用此函数(这里我使用ni变量作为示例):

ni_lag      <- do.call('rbind', by(df[ , c('datadate', 'ni')],  df$gvkey, lag.vec))

其中gvkey是特定公司的ID号,datadateYYYYMMDD形式的8位整数。

当我使用更简单的函数时,这种方法要快得多:

lag.vec.seq <- function(x){#' lag vector when all data points are present, in order

if(length(x)>1){
      y <- c(NA, x[1:(length(x)-1)])
  } else {y <- NA}
  return(y)
}

tapply命令一起使用

ni_lag      <- as.vector(unlist(tapply(df$ni,  df$gvkey, lag.vec.seq)))

正如您所看到的,主要区别在于tapply方法不包含任何datadate信息,因此该函数假设所有数据都是连续的(即,没有丢失的年份)数据帧)。由于我知道缺少年份,因此我构建了do.call - by函数来解释这一点。

一些注意事项:

1)函数中的第一个order命令可能是不必要的,因为我的数据是由gvkeydatadate提前排序的(例如df <- df[order(df$gvkey, df$datadate), ])。但是,当我使用像这样的函数式编程时,我总是有点害怕R弄乱我的行排序。这是毫无根据的恐惧吗?

2)识别减慢处理速度的因素将非常有帮助。它是变量的重命名吗?在函数中创建一个新的数据框?或者do.callby的{​​{1}}通常比tapply慢得多吗?

谢谢!

0 个答案:

没有答案