ggplot - r plot type




如何從日期獲得周數? (6)

在R中尋找一個函數將日期轉換為周數(一年)我從包data.table開始week 。 但是,我發現了一些奇怪的行為:

> 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函數的其他建議也受到讚賞。


基礎包

使用函數strftime傳遞參數%V以獲得ISO 8601中定義的十進制數(01-53)作為年份的一周。(文檔中的更多細節:?strftime)

strftime(c("2014-03-16", "2014-03-17","2014-03-18", "2014-01-01"), format = "%V")

輸出:

[1] "11" "12" "12" "01"

僅使用base,我編寫了以下函數。

注意:

  1. 假設週一是本週的第1天
  2. 第一周是第1週
  3. 如果一周是去年的52,則返回0

微調以滿足您的需求。

findWeekNo <- function(myDate){
  # Find out the start day of week 1; that is the date of first Mon in the year
  weekday <- switch(weekdays(as.Date(paste(format(as.Date(myDate),"%Y"),"01-01", sep = "-"))),
                    "Monday"={1},
                    "Tuesday"={2},
                    "Wednesday"={3},
                    "Thursday"={4},
                    "Friday"={5},
                    "Saturday"={6},
                    "Sunday"={7}
  )

  firstMon <- ifelse(weekday==1,1, 9 - weekday )

  weekNo <- floor((as.POSIXlt(myDate)$yday - (firstMon-1))/7)+1
  return(weekNo)
}


findWeekNo("2017-01-15") # 2

如果你想獲得使用年份的周數: "%YW%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


如果你想獲得年份的周數,使用strftime的Grant Shannon的解決方案可行,但你需要對1月1日左右的日期進行一些修正。 例如,2016-01-03(yyyy-mm-dd)是2015年第53週,而不是2016年。2018-12-31是2019年第1週,而不是2018年。這些代碼提供了一些示例和解決方案。 在“年周”欄目中,這些年有時是錯誤的,在“一周2”中它們被糾正(第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

我理解在某些情況下需要包,但基本語言非常優雅且經過驗證(並經過調試和優化)。

為什麼不:

dt <- as.Date("2014-03-16")
dt2 <- as.POSIXlt(dt)
dt2$yday
[1] 74

然後選擇一年中的第一周是零(如C中的索引)還是1(如R中的索引)。

沒有包可以學習,更新,擔心錯誤。


我認為問題是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.Rhttps://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軟件包的鏈接,但請不要太依賴它,因為它可能會改變,而且沒有很好的記錄。





week-number