首页 > 解决方案 > 如何使用 lapply 而不是 for 循环?

问题描述

我正在尝试计算被认为是在晚上的时间间隔内的小时数(这里从 16:00 开始计算)。下面是一个例子。

                start                 end  evening
1 2018-01-01 10:47:05 2018-01-01 16:36:03 0.600924
2 2018-01-02 04:05:56 2018-01-02 14:24:59 0.000000
3 2018-01-02 13:37:41 2018-01-03 00:47:31 5.000000
4 2018-01-02 22:53:31 2018-01-03 04:43:59 0.000000
5 2018-01-03 17:04:20 2018-01-03 22:27:39 3.927569

我做了一个函数,f_overlap()计算每行晚上的小时数。在循环中运行它for看起来像这样:

library(lubridate)

...

for (row in 1:nrow(df)) {
  df$evening[row] <- f_overlap(eveningStart,
                               eveningEnd,
                               interval(df[row,'start'], df[row,'end']))
}

我无法理解使用lapply()而不是for循环,并且我在那里阅读的教程和我在 SO 阅读的问题到目前为止还没有任何帮助。那么,有人可以在这里帮助我,向我展示您将如何获得相同的结果lapply()吗?

标签: r

解决方案


Asapply()应该很合适。

evening <- sapply(1:nrow(df1), f_overlap)
> cbind(df1, evening=evening)
                start                 end   evening
1 2018-01-01 10:47:05 2018-01-01 16:36:03 0.6008333
2 2018-01-02 04:05:56 2018-01-02 14:24:59 0.0000000
3 2018-01-02 13:37:41 2018-01-03 00:47:31 5.0000000
4 2018-01-02 22:53:31 2018-01-03 04:43:59 0.0000000
5 2018-01-03 17:04:20 2018-01-03 22:27:39 3.9277778

如果你依赖lapply()你将不得不unlist()rbind()输出:

do.call(rbind, lapply(1:nrow(df1), f_overlap))  # rbind, or
unlist(lapply(1:nrow(df1), f_overlap))  # unlist

您也可以使用cbind()上述两种替代方法。

我试图重建你的f_overlap()函数的作用,这些值至少非常相似。

f_overlap <- function(x) {
  i0 <- as.POSIXct(paste(as.character(as.Date(df1[x,]$start)), "16:00"))
  t0 <- df1[x, ]$start
  t1 <- df1[x, ]$end
  i1 <- as.POSIXct(paste(as.character(as.Date(df1[x,]$start)), "21:00"))
  if (t0 < i0 & t1 < i0) return(0)
  else if (t0 < i0 & t1 > i1) return(5)
  else if (t0 > i1 & t1 > i1) return (0)
  else if (t0 > i0 & t1 < i1) 
    return(difftime(t1, t0, units="hours"))
  else if (t0 < i0 & t1 < i1) 
    return(difftime(t1, i0, units="hours"))
  else if (t0 > i0 & t1 > i1) 
    return(difftime(i1, t0, units="hours"))
}

推荐阅读