停止将日期转换为数字的地图

时间:2016-07-18 13:26:56

标签: r dplyr lubridate

我有一个函数可以查找给定日期的一周的第一天。在这个特殊的问题上,星期四开始几周。

该功能适用​​于各个日期。

week_commencing <- function(date) {
  weekday <- lubridate::wday(date)
  if (weekday >= 5) { 
    return(date - lubridate::days(weekday) + lubridate::days(5))
  } else {
    return(date - lubridate::days(weekday) - lubridate::days(2))
  } 
}

现在,我想使用dplyr的管道。所以我修改了它以接受Map的列。

week_commencing <- function(dates) {
  Map(function(date) {
    weekday <- lubridate::wday(date)
    if (weekday >= 5) { 
      return(date - lubridate::days(weekday) + lubridate::days(5))
    } else {
      return(date - lubridate::days(weekday) - lubridate::days(2))
    } 
  },dates)
}

我认为这个功能正在运作,但是也会对日期施加一些奇怪的强制,因为我最终得到了数字日期。

> test <- data.frame(datetime=seq.Date(as.Date("2016-06-01"),as.Date("2016-06-10"), by='day'))
> test
     datetime
1  2016-06-01
2  2016-06-02
3  2016-06-03
4  2016-06-04
5  2016-06-05
6  2016-06-06
7  2016-06-07
8  2016-06-08
9  2016-06-09
10 2016-06-10

> test %>% mutate(datetime=week_commencing(datetime))
   datetime
1     16947
2     16954
3     16954
4     16954
5     16954
6     16954
7     16954
8     16954
9     16961
10    16961

关于如何结束普通日期对象的任何想法?地图总是在施加强制吗?

2 个答案:

答案 0 :(得分:3)

我不知道为什么class属性被删除(使用其他* apply函数时也是如此)。 - 内心问题似乎是unlist丢弃类:

> unlist(list(structure(1, class = 'foo')))
[1] 1

但修复很简单:最后设置类。

此外,我建议不要使用Map(返回list),而是使用vapply。然后我们离开了:

week_commencing <- function(dates) {
  wc <- function(date) {
    weekday <- lubridate::wday(date)
    if (weekday >= 5) { 
      return(date - lubridate::days(weekday) + lubridate::days(5))
    } else {
      return(date - lubridate::days(weekday) - lubridate::days(2))
    } 
  }

  structure(vapply(dates, wc, numeric(1)), class = 'Date')
}

您还可以在该功能上使用Vectorize,但这也会删除class属性。

答案 1 :(得分:2)

或者,您可以将其保留在dplyr系列中:

week_commencing <- function(date) {
  weekday <- lubridate::wday(date)
  dplyr::if_else(weekday >= 5,
                 date - lubridate::days(weekday) + lubridate::days(5),
                 date - lubridate::days(weekday) - lubridate::days(2))
}