在R中寻找一个函数将日期转换为周数(一年)我从包week
获取了data.table
。
但是,我发现了一些奇怪的行为:
> week("2014-03-16") # Sun, expecting 11
[1] 11
> week("2014-03-17") # Mon, expecting 12
[1] 11
> week("2014-03-18") # Tue, expecting 12
[1] 12
为什么星期二的周数转换为12,而不是星期一?我错过了什么? (时区应该是无关紧要的,因为只有日期?!)
对(基本)R函数的其他建议也很受欢迎。
答案 0 :(得分:44)
基础包
使用函数strftime
传递参数%V
以获取十进制数字(01-53)如ISO 8601中所定义。(文档中的更多细节:?strftime)
strftime(c("2014-03-16", "2014-03-17","2014-03-18", "2014-01-01"), format = "%V")
输出:
[1] "11" "12" "12" "01"
答案 1 :(得分:28)
如果您尝试使用lubridate:
library(lubridate)
lubridate::week(ymd("2014-03-16", "2014-03-17","2014-03-18", '2014-01-01'))
[1] 11 11 12 1
模式是一样的。试试isoweek
lubridate::isoweek(ymd("2014-03-16", "2014-03-17","2014-03-18", '2014-01-01'))
[1] 11 12 12 1
答案 2 :(得分:5)
实际上,我认为您可能在week(...)
函数中发现了一个错误,或者至少是文档中的错误。希望有人会跳进去解释我错的原因。
查看代码:
library(lubridate)
> week
function (x)
yday(x)%/%7 + 1
<environment: namespace:lubridate>
文档说明:
周数是在日期和1月1日之间发生的完整七天时段加上一个。
但是,自1月1日是一年的第一天(不是第0天),第一个&#34;周&#34;将是一个六天的时间。代码应该(??)
(yday(x)-1)%/%7 + 1
注意:您在week(...)
包中使用data.table
,这与lubridate::week
的代码相同,不同之处在于它将所有内容强制转换为整数而不是数字。所以这个函数有同样的问题(??)。
答案 3 :(得分:4)
我认为问题是week
计算以某种方式使用了一年中的第一天。我不了解内部机制,但你可以看到我对这个例子的意思:
library(data.table)
dd <- seq(as.IDate("2013-12-20"), as.IDate("2014-01-20"), 1)
# dd <- seq(as.IDate("2013-12-01"), as.IDate("2014-03-31"), 1)
dt <- data.table(i = 1:length(dd),
day = dd,
weekday = weekdays(dd),
day_rounded = round(dd, "weeks"))
## Now let's add the weekdays for the "rounded" date
dt[ , weekday_rounded := weekdays(day_rounded)]
## This seems to make internal sense with the "week" calculation
dt[ , weeknumber := week(day)]
dt
i day weekday day_rounded weekday_rounded weeknumber
1: 1 2013-12-20 Friday 2013-12-17 Tuesday 51
2: 2 2013-12-21 Saturday 2013-12-17 Tuesday 51
3: 3 2013-12-22 Sunday 2013-12-17 Tuesday 51
4: 4 2013-12-23 Monday 2013-12-24 Tuesday 52
5: 5 2013-12-24 Tuesday 2013-12-24 Tuesday 52
6: 6 2013-12-25 Wednesday 2013-12-24 Tuesday 52
7: 7 2013-12-26 Thursday 2013-12-24 Tuesday 52
8: 8 2013-12-27 Friday 2013-12-24 Tuesday 52
9: 9 2013-12-28 Saturday 2013-12-24 Tuesday 52
10: 10 2013-12-29 Sunday 2013-12-24 Tuesday 52
11: 11 2013-12-30 Monday 2013-12-31 Tuesday 53
12: 12 2013-12-31 Tuesday 2013-12-31 Tuesday 53
13: 13 2014-01-01 Wednesday 2014-01-01 Wednesday 1
14: 14 2014-01-02 Thursday 2014-01-01 Wednesday 1
15: 15 2014-01-03 Friday 2014-01-01 Wednesday 1
16: 16 2014-01-04 Saturday 2014-01-01 Wednesday 1
17: 17 2014-01-05 Sunday 2014-01-01 Wednesday 1
18: 18 2014-01-06 Monday 2014-01-01 Wednesday 1
19: 19 2014-01-07 Tuesday 2014-01-08 Wednesday 2
20: 20 2014-01-08 Wednesday 2014-01-08 Wednesday 2
21: 21 2014-01-09 Thursday 2014-01-08 Wednesday 2
22: 22 2014-01-10 Friday 2014-01-08 Wednesday 2
23: 23 2014-01-11 Saturday 2014-01-08 Wednesday 2
24: 24 2014-01-12 Sunday 2014-01-08 Wednesday 2
25: 25 2014-01-13 Monday 2014-01-08 Wednesday 2
26: 26 2014-01-14 Tuesday 2014-01-15 Wednesday 3
27: 27 2014-01-15 Wednesday 2014-01-15 Wednesday 3
28: 28 2014-01-16 Thursday 2014-01-15 Wednesday 3
29: 29 2014-01-17 Friday 2014-01-15 Wednesday 3
30: 30 2014-01-18 Saturday 2014-01-15 Wednesday 3
31: 31 2014-01-19 Sunday 2014-01-15 Wednesday 3
32: 32 2014-01-20 Monday 2014-01-15 Wednesday 3
i day weekday day_rounded weekday_rounded weeknumber
我的解决方法是这个功能: https://github.com/geneorama/geneorama/blob/master/R/round_weeks.R
round_weeks <- function(x){
require(data.table)
dt <- data.table(i = 1:length(x),
day = x,
weekday = weekdays(x))
offset <- data.table(weekday = c('Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday'),
offset = -(0:6))
dt <- merge(dt, offset, by="weekday")
dt[ , day_adj := day + offset]
setkey(dt, i)
return(dt[ , day_adj])
}
当然,您可以轻松更改偏移量,使星期一先行或其他。这样做的最好方法是在偏移量上添加一个偏移量......但我还没有这样做。
我提供了一个简单的geneorama包的链接,但请不要太依赖它,因为它可能会改变而且没有很好的记录。
答案 4 :(得分:3)
如果您想获得使用年份的周数:"%Y-W%V"
:
e.g yearAndweeks <- strftime(dates, format = "%Y-W%V")
所以
> strftime(c("2014-03-16", "2014-03-17","2014-03-18", "2014-01-01"), format = "%Y-W%V")
成为:
[1] "2014-W11" "2014-W12" "2014-W12" "2014-W01
“
答案 5 :(得分:2)
我理解在某些情况下需要包,但基本语言非常优雅且经过验证(并经过调试和优化)。
为什么不:
dt <- as.Date("2014-03-16")
dt2 <- as.POSIXlt(dt)
dt2$yday
[1] 74
然后选择一年中的第一周是零(如C中的索引)还是1(如R中的索引)。
没有包可以学习,更新,担心错误。
答案 6 :(得分:0)
仅使用base,我编写了以下函数。
注意:
根据您的需要进行微调。
xs = 0:3;
ys = 0:3;
out = [[xs[i] for i in 1:length(xs), j in 1:length(ys)][:] [ys[j] for i in 1:length(xs), j in 1:length(ys)][:]]
答案 7 :(得分:0)
如果您想获取年份的星期数,可以使用strftime解决格兰特·香农(Grant Shannon)的解决方案,但是您需要对1月1日前后的日期进行一些更正。例如,2016-01-03(yyyy-mm-dd)是2015年的第53周,而不是2016年。而2018-12-31是2019年的第1周,而不是2018年。此代码提供了一些示例和解决方案。在“ yearweek”列中,年份有时是错误的,在“ yearweek2”中,它们已被更正(第2行和第5行)。
library(dplyr)
library(lubridate)
# create a testset
test <- data.frame(matrix(data = c("2015-12-31",
"2016-01-03",
"2016-01-04",
"2018-12-30",
"2018-12-31",
"2019-01-01") , ncol=1, nrow = 6 ))
# add a colname
colnames(test) <- "date_txt"
# this codes provides correct year-week numbers
test <- test %>%
mutate(date = as.Date(date_txt, format = "%Y-%m-%d")) %>%
mutate(yearweek = as.integer(strftime(date, format = "%Y%V"))) %>%
mutate(yearweek2 = ifelse(test = day(date) > 7 & substr(yearweek, 5, 6) == '01',
yes = yearweek + 100,
no = ifelse(test = month(date) == 1 & as.integer(substr(yearweek, 5, 6)) > 51,
yes = yearweek - 100,
no = yearweek)))
# print the result
print(test)
date_txt date yearweek yearweek2
1 2015-12-31 2015-12-31 201553 201553
2 2016-01-03 2016-01-03 201653 201553
3 2016-01-04 2016-01-04 201601 201601
4 2018-12-30 2018-12-30 201852 201852
5 2018-12-31 2018-12-31 201801 201901
6 2019-01-01 2019-01-01 201901 201901