将周数转换为日期

30

我在R中有一个数据框,其中包含一年的周数,我希望将其转换为日期。我知道我需要选择一年中的某一天,因此我将这些值固定为2014年和星期一。将其转换为日期似乎很简单:

as.Date(paste(2014,df$Week,1,sep=""),"%Y%U%u")

但是这段代码只有在周数大于9时才起作用。第1-9周返回NA。如果我将周数改为01、02、03......它仍然返回NA。

有人看出我错过了什么吗?


请注意不同的周计数约定。请参见此答案进行讨论。 - Uwe
1
@Uwe 我认为最好在这里发布您的答案并将另一个 Q 标记为重复。 - Jaap
5个回答

50

as.Date因为期望两位数字的星期数并且无法正确解析,所以将1到9视为NA。

要修复它,需要添加一些“-”来分隔内容:

as.Date(paste(2014, df$Week, 1, sep="-"), "%Y-%U-%u")

r函数可以去掉数字数据中01中的“0” - 可以查看 paste(2014,01,1,sep="") 的输出结果 - "201411"。你可以使用 paste(2014,"01",1,sep="") 来将它转换为字符,但是如果你的数据是数字类型那么这不会很容易实现。 - jeremycg
5
注意不同的周计数约定。请参阅此答案进行讨论。 - Uwe

16

另一种解决方案是使用 lubridate 包中的日期算术:

lubridate::ymd( "2014-01-01" ) + lubridate::weeks( df$Week - 1 )

-1 是必须的,因为 2014-01-01 已经是第 1 周了。换句话说,我们希望:

  • df$Week == 1 对应于 2014-01-01(即 ymd("2014-01-01") + weeks(1-1)
  • df$Week == 2 对应于 2014-01-08(即 ymd("2014-01-01") + weeks(2-1)
  • 以此类推。

1
你如何将此推广以考虑到年份的变化? - Phil
3
请注意不同的周计数约定。请参阅此答案进行讨论:https://dev59.com/FVcO5IYBdhLWcg3wmSuR#45587644。 - Uwe
1
@Phil ymd("2014-01-01") + weeks(df$Week - 1) + years(df$Year - 2014)(假设有一个Year变量)。 - ahorn

6

lubridate 的另一种选项

lubridate::parse_date_time(paste(2014, df$Week, 1, sep="/"),'Y/W/w')

W - 周数, w - 星期数, 0-6 (周日至周六)


2
我已经检查过了,它运行良好。你能告诉我你得到了什么结果吗? - Yuriy Barvinchenko
[1] NA Warning message: All formats failed to parse. No formats found. - Johan Larsson
3
如果'Mon'不是你对星期一的缩写,那么地区设置可能是引起问题的原因。你可以使用数字1代表星期一,而且可以用'u'代替'a'。 lubridate::parse_date_time(paste(2014, 42, 1, sep="/"),'Y/W/u') - Yuriy Barvinchenko

2
另一种选择是确保周数有两位数字,可以使用 stringr::str_pad() 实现,它将添加一个 pad="0" 以确保有 width=2 个数字:
year <- 2015
week <- 1
as.Date(paste(year, week, "1", sep=""), "%Y%U%u")
#> [1] NA
as.Date(paste(year, stringr::str_pad(week,width=2, pad="0"), "1", sep=""), "%Y%U%u")
#> [1] "2015-01-05"
as.Date(paste(year, week, "1", sep="-"), "%Y-%U-%u")
#> [1] "2015-01-05"

本文由 reprex 包(v1.0.0)于2021年04月19日创建


-1
It will be like using 2nd year = (week-52), 3rd year  = (week -104)...so on

for(i in 1:456548)
{
  if (train[i,2] > 0 & train[i,2] <53)
  {
    train["weekdate"] <- as.Date(paste(2016, train$week, 1, sep="-"), "%Y-%U-%u")
  }
  if (train[i,2] > 52 & train[i,2] <105)
  {
    train["weekdate"] <- as.Date(paste(2017, (train$week-52), 1, sep="-"), "%Y-%U-%u")
  }
  if (train[i,2] > 104 & train[i,2] <150)
  {
    train["weekdate"] <- as.Date(paste(2018, (train$week-104), 1, sep="-"), "%Y-%U-%u")
  }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接