web-dev-qa-db-ja.com

日付から週番号を取得する方法は?

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関数に関するその他の提案も歓迎します。

46
Christian Borck

基本パッケージ

関数strftimeを使用して、引数%Vを渡して、ISO 8601で定義されているように、年の週を10進数(01〜53)で取得します。

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

出力:

[1] "11" "12" "12" "01"
48
mpalanco

潤滑油を使用する場合:

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
29

実際、week(...)関数のバグ、または少なくともドキュメントのエラーを発見したかもしれません。うまくいけば、誰かが飛び込んで、なぜ私が間違っているのかを説明してくれるでしょう。

コードを見る:

_library(lubridate)
> week
function (x) 
yday(x)%/%7 + 1
<environment: namespace:lubridate>
_

ドキュメントの状態:

週は、日付から1月1日までに発生した完全な7日間の期間に1を足した数です。

ただし、1月1日は年の最初の日(ゼロ日ではない)なので、最初の「週」は6日間になります。コードは(??)

_(yday(x)-1)%/%7 + 1
_

NB:_data.table_パッケージでweek(...)を使用していますが、これは_lubridate::week_と同じコードですが、効率のためにすべてを数値ではなく整数に強制します。したがって、この関数には同じ問題があります(??)。

6
jlhoward

年を使用して週番号を取得する場合は、"%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 "

4
Grant Shannon

問題は、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])
}

もちろん、月曜日を最初にするなど、オフセットを簡単に変更できます。これを行う最良の方法は、オフセットにオフセットを追加することですが、まだそれを行っていません。

単純なジェネララパッケージへのリンクを提供しましたが、変更される可能性が高く、あまり文書化されていないため、あまり頼りすぎないでください。

4
geneorama

特定の状況ではパッケージの必要性を理解していますが、基本言語は非常に洗練されており、実証済みです(そしてデバッグおよび最適化されています)。

何故なの:

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

そして、年の最初の週がゼロ(Cのインデックス付けの場合)か1(Rのインデックス付けの場合)かを選択します。

学習、更新、バグの心配をするパッケージはありません。

4
user3229754

年の週番号を取得する場合、strftimeを使用したGrant Shannonのソリューションは機能しますが、1月1日前後の日付を修正する必要があります。たとえば、2016-01-03(yyyy-mm-dd)は2016年ではなく2015年の53週目です。そして2018-12-31は2018年ではなく2019年の1週目です。このコードはいくつかの例と解決策を提供します。 「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

0
Erik Volkers

ベースのみを使用して、次の関数を作成しました。

注意:

  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
0
Wael Hussein