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

Start first day of week of the year on Sunday and end last day of week of the year on Saturday

我最近在 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

任何人都可以指出一个方向来实现自动化,这样我就不必每年更改代码了吗?

我们可以在逻辑向量

上使用 cumsum
df$WKN <- unique(df$WKN)[cumsum(df$weeknum==1) +1]
df$WKN
#[1] 52 53 53 53 53 53 53 53  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')))

这return是一回事。 lubridate 的 isoweek 功能是等价的,所以你也可以做

library(lubridate)

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

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

两者 return 与 as.integer(format(...)) 版本的结果相同。

考虑到你用的是lubridate,我也想给你一个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/year 的两边添加一周来创建一个两周的时间段。
  3. 计算当年的各种汇总统计数据以供您启迪。
  4. 挑出第二个星期天。按照设计,1/1/年始终是第 8 个条目。
  5. 如果星期日是该月的第一天,它不会执行任何操作。
  6. 否则它会覆盖一年中的第几周,以便一年中的第一周从第二个星期日开始。

这是

的结果
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