R:如何获得当月的周数

标签 r date

我是 R 的新手。
我想要日期所属的月份的周数。

通过使用以下代码:

>CurrentDate<-Sys.Date()
>Week Number <- format(CurrentDate, format="%U")
>Week Number
"31"

%U 将返回一年中的周数。
但我想要一个月的周数。
如果日期是 2014 年 8 月 1 日,那么我想得到 1。(日期属于该月的第一周)。

例如:
2014-09-04 -> 1(日期属于该月的第一周)。
2014-09-10 -> 2(日期属于该月的第 2 周)。
等等...

我怎样才能得到这个?

引用:
http://astrostatistics.psu.edu/su07/R/html/base/html/strptime.html

最佳答案

问题概述

很难判断哪个答案有效,所以我构建了自己的函数 nth_week 并针对其他人进行了测试。

导致大多数答案不正确的问题是:

  • 一个月的第一周通常很短
  • 与本月最后一周相同

  • 例如,2019 年 10 月 1 日是星期二,因此 10 月后的 6 天(即星期日)已经是第二周。此外,连续月份通常在各自的计数中共享同一周,这意味着上个月的最后一周通常也是当月的第一周。因此,我们应该期望每周计数高于每年 52 周,并且某些月份包含 6 周的跨度。

    结果比较

    下表显示了上述一些建议算法出错的示例:
    DATE            Tori user206 Scri Klev Stringi Grot Frei Vale epi iso coni
    Fri-2016-01-01    1     1      1   1      5      1    1    1    1   1   1
    Sat-2016-01-02    1     1      1   1      1      1    1    1    1   1   1
    Sun-2016-01-03    2     1      1   1      1      2    2    1  -50   1   2
    Mon-2016-01-04    2     1      1   1      2      2    2    1  -50 -51   2
    ----
    Sat-2018-12-29    5     5      5   5      5      5    5    4    5   5   5
    Sun-2018-12-30    6     5      5   5      5      6    6    4  -46   5   6
    Mon-2018-12-31    6     5      5   5      6      6    6    4  -46 -46   6
    Tue-2019-01-01    1     1      1   1      6      1    1    1    1   1   1
    

    你可以看到只有 Grothendieck、conighion、Freitas 和 Tori 是正确的,因为他们处理了部分周期间。我比较了从 100 年到 3000 年的所有日子;这 4 个之间没有区别。(Stringi 可能是正确的,因为将周末标记为单独的、递增的时段,但我没有检查确定;epiweek() 和 isoweek(),因为它们的预期用途,表现出一些奇怪的行为接近年底时使用它们来增加周数。)

    速度比较

    以下是以下实现之间的效率测试:Tori、Grothendieck、Conighion 和 Freitas
    # prep
    library(lubridate)
    library(tictoc)
    
    kepler<- ymd(15711227) # Kepler's birthday since it's a nice day and gives a long vector of dates
    some_dates<- seq(kepler, today(), by='day')
    
    
    # test speed of Tori algorithm
    tic(msg = 'Tori')
    Tori<- (5 + day(some_dates) + wday(floor_date(some_dates, 'month'))) %/% 7
    toc()
    Tori: 0.19 sec elapsed
    
    # test speed of Grothendieck algorithm
    wk <- function(x) as.numeric(format(x, "%U"))
    tic(msg = 'Grothendieck')
    Grothendieck<- (wk(some_dates) - wk(as.Date(cut(some_dates, "month"))) + 1)
    toc()
    Grothendieck: 1.99 sec elapsed
    
    # test speed of conighion algorithm
    tic(msg = 'conighion')
    weeknum <- as.integer( format(some_dates, format="%U") )
    mindatemonth <- as.Date( paste0(format(some_dates, "%Y-%m"), "-01") )
    weeknummin <- as.integer( format(mindatemonth, format="%U") ) # the number of the week of the first week within the month
    conighion <- weeknum - (weeknummin - 1) # this is as an integer
    toc()
    conighion: 2.42 sec elapsed
    
    # test speed of Freitas algorithm
    first_day_of_month_wday <- function(dx) {
       day(dx) <- 1
       wday(dx)
     }
    tic(msg = 'Freitas')
    Freitas<- ceiling((day(some_dates) + first_day_of_month_wday(some_dates) - 1) / 7)
    toc()
    Freitas: 0.97 sec elapsed
    

    最快的正确算法大约至少 5 倍

    require(lubridate)

    (5 + day(some_dates) + wday(floor_date(some_dates, 'month'))) %/% 7


    # some_dates above is any vector of dates, like:
    some_dates<- seq(ymd(20190101), today(), 'day')
    

    功能实现

    我还为它编写了一个通用函数,它执行月或年周计数,从您选择的一天开始(即假设您想从星期一开始您的一周),标记输出以便于检查,并且由于 lubridate 仍然非常快.
    nth_week<- function(dates = NULL,
                        count_weeks_in = c("month","year"),
                        begin_week_on = "Sunday"){
    
      require(lubridate)
    
      count_weeks_in<- tolower(count_weeks_in[1])
    
      # day_names and day_index are for beginning the week on a day other than Sunday
      # (this vector ordering matters, so careful about changing it)
      day_names<- c("Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday")
    
      # index integer of first match
      day_index<- pmatch(tolower(begin_week_on),
                         tolower(day_names))[1]
    
    
      ### Calculate week index of each day
    
      if (!is.na(pmatch(count_weeks_in, "year"))) {
    
        # For year:
        # sum the day of year, index for day of week at start of year, and constant 5 
        #  then integer divide quantity by 7   
        # (explicit on package so lubridate and data.table don't fight)
        n_week<- (5 + 
                    lubridate::yday(dates) + 
                    lubridate::wday(floor_date(dates, 'year'), 
                                    week_start = day_index)
        ) %/% 7
    
      } else {
    
        # For month:
        # same algorithm as above, but for month rather than year
        n_week<- (5 + 
                    lubridate::day(dates) + 
                    lubridate::wday(floor_date(dates, 'month'), 
                                    week_start = day_index)
        ) %/% 7
    
      }
    
      # naming very helpful for review
      names(n_week)<- paste0(lubridate::wday(dates,T), '-', dates)
    
      n_week
    
    }
    

    功能输出
    # Example raw vector output: 
    some_dates<- seq(ymd(20190930), today(), by='day')
    nth_week(some_dates)
    
    Mon-2019-09-30 Tue-2019-10-01 Wed-2019-10-02 
                 5              1              1 
    Thu-2019-10-03 Fri-2019-10-04 Sat-2019-10-05 
                 1              1              1 
    Sun-2019-10-06 Mon-2019-10-07 Tue-2019-10-08 
                 2              2              2 
    Wed-2019-10-09 Thu-2019-10-10 Fri-2019-10-11 
                 2              2              2 
    Sat-2019-10-12 Sun-2019-10-13 
                 2              3 
    
    # Example tabled output:
    library(tidyverse)
    
    nth_week(some_dates) %>% 
      enframe('DATE','nth_week_default') %>% 
      cbind(some_year_day_options = as.vector(nth_week(some_dates, count_weeks_in = 'year', begin_week_on = 'Mon')))
    
                 DATE nth_week_default some_year_day_options
    1  Mon-2019-09-30                5                    40
    2  Tue-2019-10-01                1                    40
    3  Wed-2019-10-02                1                    40
    4  Thu-2019-10-03                1                    40
    5  Fri-2019-10-04                1                    40
    6  Sat-2019-10-05                1                    40
    7  Sun-2019-10-06                2                    40
    8  Mon-2019-10-07                2                    41
    9  Tue-2019-10-08                2                    41
    10 Wed-2019-10-09                2                    41
    11 Thu-2019-10-10                2                    41
    12 Fri-2019-10-11                2                    41
    13 Sat-2019-10-12                2                    41
    14 Sun-2019-10-13                3                    41
    

    希望这项工作可以节省人们必须清除所有响应以找出正确答案的时间。

    关于R:如何获得当月的周数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25199851/

    相关文章:

    r - 使用aggregate.data.frame函数汇总r data.frame中的数据

    java - 通过 Intent 将时间和日期添加到谷歌日历

    ios - Dateformatter 日期字符串返回 nil

    MySQL 在不加入临时表的情况下使用 GROUP BY DATE(table.timestamp) 时填写缺失的日期

    java - 为什么日期时间的毫秒数 1-1-1970 00 :00:00 is in negative?

    r - 通过提取相似的列名跨列应用函数

    r - 使用 Shiny 时出现 413 请求错误

    Rscript - 摆脱 "WARNING: ignoring environment value of R_HOME"

    r - 函数 "extract"如何处理不同的投影?

    php - 如何在mySQL中将当前日期设置为默认日期