优化大数据帧上的映射函数

时间:2017-11-03 09:52:32

标签: r optimization mapply date-difference

我有以下创建函数用于我的工作目的:

monthsCounter <- function(date1, date2) {
  if (date2 < date1) {
    warning("Can't calculate result if second date is older than first date")
  } else {
    date1_Y <- as.numeric(format(date1, '%Y'))
    date2_Y <- as.numeric(format(date2, '%Y'))
    date1_M <- as.numeric(format(date1, '%m'))
    date2_M <- as.numeric(format(date2, '%m'))
    if (date2_Y == date1_Y) {
      date2_M - date1_M
    } else if (date2_M < date1_M) {
      max(0, date2_Y - date1_Y - 1)*12 + 12 - date1_M + date2_M
    } else {
      max(0, date2_Y - date1_Y)*12 + date2_M - date1_M
    }
  }
}

在一个坚果中,无论月份日期如何,它都会在两个日期之间计算几个月。 当我在我的数据框中mapply时:

allData$monthsSinceIssue <- mapply(monthsCounter, allData$start_month, allData$Date)

计算需要很长时间。

问题:您对如何优化我的功能以使其计算更快有任何建议吗?

更新:基于@Sotos和@MrGumble的建议我最终得到了这个功能:

monthsCounter <- function(date1, date2) {
  date1_Y <- as.numeric(format(date1, '%Y'))
  date2_Y <- as.numeric(format(date2, '%Y'))
  date1_M <- as.numeric(format(date1, '%m'))
  date2_M <- as.numeric(format(date2, '%m'))
  ifelse(date2 < date1, NA,
         ifelse(date2_Y == date1_Y, date2_M - date1_M,
                ifelse(date2_M < date1_M, max(0, date2_Y - date1_Y - 1)*12 + 12 - date1_M + date2_M, max(0, date2_Y - date1_Y)*12 + date2_M - date1_M)))
}

将我的计算时间从 3.5分钟减少到2秒!

UPDATE2:我偶然发现了@MrGumble可能指向的问题。 date2 - date1 > 1时的情况。 因此不得不更新功能:

monthsCounter <- function(date1, date2) {
  date1_Y <- as.numeric(format(date1, '%Y'))
  date2_Y <- as.numeric(format(date2, '%Y'))
  date1_M <- as.numeric(format(date1, '%m'))
  date2_M <- as.numeric(format(date2, '%m'))
  ifelse(date2 < date1, NA,
         ifelse(date2_Y == date1_Y, date2_M - date1_M,
                ifelse(date2_M < date1_M, pmax(0, date2_Y - date1_Y - 1)*12 + 12 - date1_M + date2_M, pmax(0, date2_Y - date1_Y)*12 + date2_M - date1_M)))
}

基本上将max更改为pmax

1 个答案:

答案 0 :(得分:1)

R固有地适用于矢量。您的函数可以轻松地接受两列作为参数:

allData$monthsSinceIssue <- monthsCounter(allData$start_month, allData$Date)

虽然您必须将max更改为pmax。也可以像Sotos建议的那样(更新到ifelse功能)。 最后,我建议你返回NA而不是警告。