从星期日开始一年中的第一天,并在星期六结束一年中的最后一天

时间:2016-07-26 03:13:14

标签: r date datetime dplyr lubridate

我最近遇到了R处理日期的问题。 2015年(2015-12-31)的最后一天是星期四,这意味着如果我将星期日视为我一周的开始日,那么今年的最后一周只包含5天。现在,我希望2016-01-01和2016-01-02(周五和周六)与第53周相关联,并在2016-01-03开始第1周,这是在周日。

require(lubridate)
range <- seq(as.Date('2015-12-26'), by = 1, len = 10)
df <- data.frame(range)
df$WKN <- as.numeric(strftime(df$range, format = "%U")) + 1
df$weekday <- weekdays(df$range)
df$weeknum <- wday(df$range)

这会给我以下结果:

df:
range      WKN   weekday   weeknum
2015-12-26  52  Saturday       7
2015-12-27  53    Sunday       1
2015-12-28  53    Monday       2
2015-12-29  53   Tuesday       3
2015-12-30  53 Wednesday       4
2015-12-31  53  Thursday       5
2016-01-01   1    Friday       6
2016-01-02   1  Saturday       7
2016-01-03   2    Sunday       1
2016-01-04   2    Monday       2

现在我希望我的数据框如下:

df:
range      WKN   weekday   weeknum
2015-12-26  52  Saturday       7
2015-12-27  53    Sunday       1
2015-12-28  53    Monday       2
2015-12-29  53   Tuesday       3
2015-12-30  53 Wednesday       4
2015-12-31  53  Thursday       5
2016-01-01  53    Friday       6
2016-01-02  53  Saturday       7
2016-01-03   1    Sunday       1
2016-01-04   1    Monday       2

有人能指出我自动化的方向,以便我不必每年都更改代码吗?

3 个答案:

答案 0 :(得分:1)

我们可以在逻辑向量上使用cumsum

df$WKN <- unique(df$WKN)[cumsum(df$weeknum==1) +1]
df$WKN
#[1] 52 53 53 53 53 53 53 53  1  1

答案 1 :(得分:1)

如果您查看?strptime,则可以使用几个不同的周号代币来format使用。这里%V几乎可以正常工作,除了它从星期一开始,所以添加一个来调整:

df$WKN <- as.integer(format(df$range + 1, '%V'))

df
##         range WKN   weekday weeknum
## 1  2015-12-26  52  Saturday       7
## 2  2015-12-27  53    Sunday       1
## 3  2015-12-28  53    Monday       2
## 4  2015-12-29  53   Tuesday       3
## 5  2015-12-30  53 Wednesday       4
## 6  2015-12-31  53  Thursday       5
## 7  2016-01-01  53    Friday       6
## 8  2016-01-02  53  Saturday       7
## 9  2016-01-03   1    Sunday       1
## 10 2016-01-04   1    Monday       2

或者如果你像标签建议那样使用dplyr,

library(dplyr)

df %>% mutate(WKN = as.integer(format(range + 1, '%V')))

返回相同的东西。 lubridate的isoweek函数是等价的,所以你也可以这样做

library(lubridate)

df$WKN <- isoweek(df$range + 1)

df %>% mutate(WKN = isoweek(range + 1))

两者都会向as.integer(format(...))版本返回相同的结果。

答案 2 :(得分:1)

考虑到您正在使用lubridate,我还想给您一个重要的解决方案。您还要求提供适用于其他年份的解决方案。这是:

adjust_first_week<- function(year){

    first <- floor_date(dmy(paste0("1-1-", year)), "year") 
    two_weeks <- c(first - days(7:1), first + days(0:6))

    df <- data.frame(date = two_weeks,
               day_of_week = weekdays(two_weeks),
               day_of_year = yday(two_weeks),
               week_of_year = week(two_weeks))

    last_weekend <- which(df$day_of_week == "Sunday")[2] -1
    df$adjust_week <- df$week_of_year
    if(last_weekend ==7) return(df)
    else{
      df$adjust_week[8:last_weekend] <- rep(53,length(8:last_weekend))
    }
    return(df)
  }
  1. 需要一个数字年份,并在该年的第一天。
  2. 通过在1/1 /年的任一侧追加一周来创建两周的时间。
  3. 为您的启发计算该年度的各种摘要统计信息。
  4. 挑出第二个星期天。按设计1/1 /年始终是第8项。
  5. 如果星期日是这个月的第一天,它就什么都不做。
  6. 否则它会覆盖一年中的一周,以便一年中的第一周从第二个星期日开始。
  7. 以下是

    的结果
    adjust_last_week(2016)
             date day_of_week day_of_year week_of_year adjust_week
    1  2015-12-25      Friday         359           52          52
    2  2015-12-26    Saturday         360           52          52
    3  2015-12-27      Sunday         361           52          52
    4  2015-12-28      Monday         362           52          52
    5  2015-12-29     Tuesday         363           52          52
    6  2015-12-30   Wednesday         364           52          52
    7  2015-12-31    Thursday         365           53          53
    8  2016-01-01      Friday           1            1          53
    9  2016-01-02    Saturday           2            1          53
    10 2016-01-03      Sunday           3            1           1
    11 2016-01-04      Monday           4            1           1
    12 2016-01-05     Tuesday           5            1           1
    13 2016-01-06   Wednesday           6            1           1
    14 2016-01-07    Thursday           7            1           1