【问题标题】:Lapply to determine months between columns in a list (of data.frames)Lapply 确定列表(data.frames)中列之间的月份
【发布时间】:2018-03-22 03:48:19
【问题描述】:

上下文

List1 是一个包含 3 个 data.frames 的列表对象,其中包含 2 个日期列。我正在尝试查找 date1 和 date2 之间的月数。测试数据和我尝试使用 lapply 的解决方案如下。我相信嵌套 lapply 中的 if 语句是必要的,因为如果 'to' 日期在 'from' 日期之前, seq.Date 会失败。

但是,我当前的实现给了我以下错误:

Error: unexpected '}' in "    }"

阅读this detailed response 表明有几件事可以给出该错误消息,但我认为我的 lapply 函数没有这些。

我之前在 for 循环中实现了这一点,但试图学习如何在我的 R 代码中将 for 循环转换为 lapply 并使用列表。

可重现的数据

set.seed(3)
sim_list = replicate(n = 3,
                     expr = {data.frame(date1 = sample(x = 1:12, size = 10), date2 = sample(x = 1:12, size = 10))},
                     simplify = F)

list1 <- lapply(sim_list, function(x) {
  x[['date1']] = as.Date(paste('01', x[['date1']], '2016', sep = '-'), format = '%d-%m-%Y')
  x[['date2']] = as.Date(paste('01', x[['date2']], '2016', sep = '-'), format = '%d-%m-%Y')
  return(x)
})

预期输出示例

> list1[[1]]
        date1      date2 elapsed_months
1  2016-03-01 2016-07-01              4
2  2016-09-01 2016-06-01              3
3  2016-04-01 2016-11-01              7
4  2016-12-01 2016-10-01              2
5  2016-05-01 2016-12-01              7
6  2016-08-01 2016-09-01              1
7  2016-01-01 2016-01-01              0
8  2016-02-01 2016-04-01              2
9  2016-11-01 2016-05-01              6
10 2016-07-01 2016-08-01              1

麻烦的 lapply 实现

lapply(list1, function(x)
  lapply(x, function(y) {
    if (y['date2'] > y['date1'] == T) {
      y['elapsed_months'] = length(seq.Date(from = y['date1'], to = y['date2'], by = 'month')) - 1
    } else {
      y['elapsed_months'] = length(seq.Date(from = y['date2'], to = y['date1'], by = 'month')) - 1
    }
  }))

感谢阅读!

【问题讨论】:

  • 另外,您的可重现数据不可重现并引发错误。
  • @RonakShah 我已经修复了示例数据。
  • @MauritsEvers 感谢分享相关帖子,我实际上在我的 lapply 函数中实现了 Dominic 的方法。我的问题不一定是如何找到日期之间的差异,而是如何将其推广到多个 data.frame。
  • 已添加示例输出!

标签: r nested lapply


【解决方案1】:

我们可以用difftime计算两个日期的天数之差,然后除以30得到月份。

lapply(list1, function(x) cbind(x, elapsed_months = 
         as.numeric(round(abs(difftime(x$date2,x$date1, units = "days")/30)))))

#[[1]]
#        date1      date2 elapsed_months
#1  2016-03-01 2016-07-01         4
#2  2016-09-01 2016-06-01         3
#3  2016-04-01 2016-11-01         7
#4  2016-12-01 2016-10-01         2
#5  2016-05-01 2016-12-01         7
#6  2016-08-01 2016-09-01         1
#7  2016-01-01 2016-01-01         0
#8  2016-02-01 2016-04-01         2
#9  2016-11-01 2016-05-01         6
#10 2016-07-01 2016-08-01         1

#[[2]]
#        date1      date2 elapsed_months
#1  2016-03-01 2016-05-01         2
#2  2016-01-01 2016-12-01        11
#3  2016-02-01 2016-02-01         0
#4  2016-11-01 2016-11-01         0
#5  2016-10-01 2016-03-01         7
#6  2016-06-01 2016-08-01         2
#7  2016-04-01 2016-06-01         2
#8  2016-05-01 2016-10-01         5
#9  2016-12-01 2016-07-01         5
#10 2016-07-01 2016-01-01         6

#[[3]]
#        date1      date2 elapsed_months
#1  2016-04-01 2016-03-01         1
#2  2016-09-01 2016-12-01         3
#3  2016-02-01 2016-09-01         7
#4  2016-06-01 2016-10-01         4
#5  2016-12-01 2016-07-01         5
#6  2016-10-01 2016-08-01         2
#7  2016-01-01 2016-11-01        10
#8  2016-11-01 2016-02-01         9
#9  2016-07-01 2016-01-01         6
#10 2016-03-01 2016-04-01         1

【讨论】:

  • 您好 Ronak,我现在已将您的答案标记为答案。随着列表大小的增加,您的代码要快得多。我已经将列表复制了 100 次,现在每个 data.frame 中有 500 行。您的代码经过的时间是 0.03 秒,而 @smankski 需要 5.59 秒。
【解决方案2】:

我无法让您的可重现结果发挥作用,但我认为您正在寻找类似的东西。

set.seed(3)
sim_list = replicate(n = 3, expr = {data.frame(date1 = sample(x = 1:12, size = 10), date2 = sample(x = 1:12, size = 10))},
                     simplify = F)  
list1 <- lapply(sim_list, function(x) {
  x['date1'] = as.Date(paste('01', unlist(x['date1']), '2016', sep = '-'), format = '%d-%m-%Y')
  x['date2'] = as.Date(paste('01', unlist(x['date2']), '2016', sep = '-'), format = '%d-%m-%Y')
  return(x)
})



lapply(list1, function(x){
  x['elapsed_months'] <- apply(x, 1,  function(y){
    abs(as.POSIXlt(as.Date(y['date1']))$mon-as.POSIXlt(as.Date(y['date2']))$mon)
  })
  x
})

【讨论】:

  • 这行得通,甚至不需要嵌套的 if 语句!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-14
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多