【问题标题】:Date component will not calculate over change in Year日期部分不会计算年份的变化
【发布时间】:2018-02-08 00:32:47
【问题描述】:

伙计,处理日期很难!

我有以下数据,并且正在尝试应用 Tidyverse 原则并使用 lubridate 作为日期组件

dates <- data.frame(date = as.Date(c('2017-12-17',
                                     '2017-12-28',
                                     '2018-01-03', 
                                     '2018-01-19')))

我想为每个日期定义年份和星期几,这很简单。

new <- dates %>%
             mutate(c_year = year(date),
                    c_week = week(date))

我真正想知道的是每个“c_year”的“c_week”开始的确切日期(ymd)。但是,当我想计算“c_week”的开始时,我没有使用 floor_date() 的原始完整日期。所以我在互联网上四处寻找,发现这段代码(大部分)可以很好地计算新的 's_create_wk' 变量,顺便说一句,我希望星期一是一周的开始:

new <- dates %>%
             mutate(c_year = year(date),
                    c_week = week(date),
                    s_create_wk = as.Date(paste0(c_year,c_week, "1"),
                                          "%Y%W%u"))

所以理论上我应该得到:

        date   c_year   c_week  start_of_wk 
1 2017-12-17     2017       51   2017-12-11
2 2017-12-28     2017       53   2017-12-25
3 2018-01-03     2018        1   2018-01-01
4 2018-01-19     2018        3   2018-01-15

但我实际上得到的是:

        date   c_year   c_week  start_of_wk 
1 2017-12-17     2017       51   2017-12-18
2 2017-12-28     2017       52   2017-12-25
3 2018-01-03     2018        1           NA
4 2018-01-19     2018        3           NA

查看我的 Outlook 日历,2017-12-25 应该在第 53 周,但无论我使用“week()”还是“isoweek()”,我都会得到如图所示的实际值。这令人困惑,因为第 51 周对于 2017-12-17 的原始日期是正确的。此外,'start_of_wk' 为 'c_week' 计算延迟一周 - 这很令人困惑。如果我减去 7 天,我会得到正确的 'c_week' 'start-of-wk',但这似乎是错误的做法。

长话短说,最大的问题是我在 2018 年的日期为“start_of_wk”获得了 NA,我不知道为什么!!

对不起,如果这令人困惑,但这肯定会让我大吃一惊。我猜日期的格式计算's_create_wk'是错误的,但我尝试了很多组合(Uu,Vv,Ww),或者我使用了错误的包或错误的函数来处理日期组件正确。

感谢您的帮助。

【问题讨论】:

  • 如果您详细说明它不再出现在您的数据中的原因(例如,如果您使用 group_by 总结),我们也许能够在问题的早期找到解决方案?
  • 在不重新创建所有代码的情况下,我会在数据加载后立即生成“c_week”,然后按“c_week”进行汇总,然后进行连接操作,其中“by”之一字段是“c_week”。 'c_week' 的一周开始的计算是在结果连接集上执行的,并且 NA 的问题出现了。下面 Calum You 的第二个编辑解决方案解决了我与 NA 的直接问题。
  • 明白了。很高兴您的问题得到了解决!
  • 是的,约会可能会很痛苦。 R 知道一年中的 3 种不同定义:美国、英国和 ISO 8601 约定(有关详细信息,请参阅 here)。你用的是哪一个?另请注意,一周的第一天的定义不同,美国定义为星期日,而英国和 ISO 定义为星期一。

标签: r date components tidyverse lubridate


【解决方案1】:

我认为这可以满足您的需求,尽管它需要一个额外的函数定义才能在管道中工作。 lubridate 有一个 wday 函数来设置星期几,特别是 wday(x) &lt;- 1 会将日期 x 更改为该周开始的日期。参数week_start 控制将哪一天视为一周的开始;在这里,我选择星期一开始一周以适应您想要的输出。

编辑:为了解决关于第 2 行是第 52 周而不是第 53 周的问题,根据我的计数2017-12-28 是在第 52 周,无论您如何计算它。例如,参见 week(ymd("2017-12-30")),这是一年中的第 364 天,因此在第 52 周 (52 * 7 = 364),而 week(ymd("2012-12-31")) 按预期返回 53。

library(tidyverse)
dates <- tibble(date = c('2017-12-17', '2017-12-28', '2018-01-03', '2018-01-19'))

wk_start <- function(date){
  wk_st <- date
  wday(wk_st, week_start = 1) <- 1
  return(wk_st)
}

dates %>%
  mutate(date = ymd(date)) %>%
  mutate(year = year(date),
         week = week(date)
         ) %>%
  mutate(start_of_wk = wk_start(date))
# A tibble: 4 x 4
  date        year  week start_of_wk
  <date>     <dbl> <dbl> <date>     
1 2017-12-17  2017 51.0  2017-12-11 
2 2017-12-28  2017 52.0  2017-12-25 
3 2018-01-03  2018  1.00 2018-01-01 
4 2018-01-19  2018  3.00 2018-01-15 

EDIT2:我四处寻找,我认为您的 as.Date 方法不起作用的原因是因为数字没有正确的间距。查看 paste0(c_year, c_week, "1") 的结果。相反,这种插入垫片的类似方法确实提供了除了第一行之外的所需输出,我仍在考虑:

dates %>%
  mutate(c_year = year(date),
         c_week = week(date),
         s_create_wk = as.Date(str_c(c_year, c_week, "1", sep = "-"), "%Y-%W-%u")
         )
# A tibble: 4 x 4
  date       c_year c_week s_create_wk
  <chr>       <dbl>  <dbl> <date>     
1 2017-12-17   2017  51.0  2017-12-18 
2 2017-12-28   2017  52.0  2017-12-25 
3 2018-01-03   2018   1.00 2018-01-01 
4 2018-01-19   2018   3.00 2018-01-15 

【讨论】:

  • Calum 您,感谢您的帮助,您的第二次编辑是对我来说效果最好/最简单的解决方案,但我也喜欢函数解决方案。我会认为一年中的一周结果是正确的。我确定问题在于使用的日历标准以及一周的哪一天开始,这很容易让人感到困惑。再次感谢。
  • 好的!我会检查您的应用程序是否使 12 月 18 日开始为 12 月 17 日这一事实是否有问题 - 这对我来说似乎不正确,但 strptime 格式逻辑的文档记录不如 lubridate 好。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-31
  • 1970-01-01
  • 2010-11-09
  • 2011-02-26
  • 2015-06-20
相关资源
最近更新 更多