在大数据框架上优化映射函数
Optimising mapply'ied function over large data frame
我为工作目的创建了以下函数:
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
。
R 天生就可以很好地处理向量。您的函数可以轻松地接受两列作为参数:
allData$monthsSinceIssue <- monthsCounter(allData$start_month, allData$Date)
尽管您必须将 max
更改为 pmax
。也按照 Sotos 的建议进行(更新到 ifelse
函数)。
最后我建议你 return NA
而不是警告。
我为工作目的创建了以下函数:
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
。
R 天生就可以很好地处理向量。您的函数可以轻松地接受两列作为参数:
allData$monthsSinceIssue <- monthsCounter(allData$start_month, allData$Date)
尽管您必须将 max
更改为 pmax
。也按照 Sotos 的建议进行(更新到 ifelse
函数)。
最后我建议你 return NA
而不是警告。