【问题标题】:Rounding dates with round_date() in R在 R 中使用 round_date() 舍入日期
【发布时间】:2021-05-17 00:03:49
【问题描述】:

我尝试仅在 R 中转换 yyyy 中的日期格式 yyyymmdd。 在how to convert numeric only year in Date in R? 中提出了一个非常有趣的答案,因为它设法让 R 理解将 8 位条目 (yyyymmdd) 转换为 4 位数字年份 (yyyy) 在润滑包中,这对我来说非常好。

在旧代码中,我使用了round_date()

   date2<-c('01/01/2000','08/08/2000','16/03/2001','25/12/2000','29/02/2000')
    name<-c('A','B','C','D','E')
    
    df<-data.frame(date2,name)
    
    df2 <- df %>%
      mutate(date2 = dmy(date2)) %>%
      mutate(year_date = round_date(date2,'year'))
    
    df2
    str(df2)

date2<date> name<chr> year_date <date>
2000-01-01    A         2000-01-01      
2000-08-08    B         2001-01-01      
2001-03-16    C         2001-01-01      
2000-12-25    D         2001-01-01      
2000-02-29    E         2000-01-01  

但是当我发现例如日期 2000-08-08 被四舍五入到 2001-01-01 年,而不是我预期的 2001-01-01 年时,我的统计分析开始出现问题。

这对我来说是一个非常大的问题,因为考虑到我的数据库中有超过 1400 行,属于 2005 年的信息已移至 2006 年。

我注意到年中(六月之后)之后的日期被四舍五入到下一年,这很糟糕。

如何将 2000-08-08 日期舍入为 2000 而不是 2001?

【问题讨论】:

    标签: r lubridate


    【解决方案1】:

    这个(更简单,也只有基本 R)操作难道不是你想要的吗?

    > date2 <- c('01/01/2000','08/08/2000','16/03/2001','25/12/2000','29/02/2000')
    > dd <- as.Date(date2, "%d/%m/%Y")
    > yd <- format(dd, "%Y-01-01")
    > dt <- as.Date(yd)
    > D <- data.frame(date2=date2, date=dd, y=yd, d=dt)
    > D
           date2       date          y          d   
    1 01/01/2000 2000-01-01 2000-01-01 2000-01-01
    2 08/08/2000 2000-08-08 2000-01-01 2000-01-01
    3 16/03/2001 2001-03-16 2001-01-01 2001-01-01
    4 25/12/2000 2000-12-25 2000-01-01 2000-01-01
    5 29/02/2000 2000-02-29 2000-01-01 2000-01-01
    >   
    

    本质上,我们只是从(解析为日期)Date 对象中提取年份组件并附加-01-01

    编辑:对于DateDatetime 对象也有trunc() 操作。奇怪的是,多年来的截断仅适用于 Datetime(有关更多信息,请参见 trunc.Date 的帮助页面),所以这也适用:

    > as.Date(trunc(as.POSIXlt(dd), "years"))
    [1] "2000-01-01" "2000-01-01" "2001-01-01" "2000-01-01" "2000-01-01"
    > 
    

    编辑 2: 我们可以在data.frame 中使用更简洁/更简单的解决方案中的最后一步,其中三列用于输入 数据(作为字符),解析数据为正确的Date类型和所需的截断年份数据——所有这些都使用基础R,没有进一步的依赖关系。当然,如果您想要可以通过管道重写它,lubridate 通过稍慢的路线获得相同的结果(这只对“大”数据很重要)。

    > date2 <- c('01/01/2000','08/08/2000','16/03/2001','25/12/2000','29/02/2000')
    > pd <- as.Date(date2, "%d/%m/%Y")
    > td <- as.Date(trunc(as.POSIXlt(pd), "years"))
    > D <- data.frame(input = date2, parsed = pd, output = td)
    > D
           input     parsed     output
    1 01/01/2000 2000-01-01 2000-01-01
    2 08/08/2000 2000-08-08 2000-01-01
    3 16/03/2001 2001-03-16 2001-01-01
    4 25/12/2000 2000-12-25 2000-01-01
    5 29/02/2000 2000-02-29 2000-01-01
    > 
    

    对于真正的“生产”用途,您可能不需要data.frame,也不需要保留导致单线的中间结果:

    > as.Date(trunc(as.POSIXlt( as.Date(date2, "%d/%m/%Y") ), "years"))
    [1] "2000-01-01" "2000-01-01" "2001-01-01" "2000-01-01" "2000-01-01"
    > 
    

    这可能是您可以获得的最紧凑和最有效的转换。

    【讨论】:

    • 查看我的更新答案。使用 typed 表示可以更安全地进行编程,因此我建议尽快转换为 Date。您仍然可以使用您喜欢的任何附加包中的任何附加功能,但它们确实使用底层的基本 R 类型。它们是基本的构建块——正如您所见,您可以混合搭配。
    • 因为它是标准的 ISO 8601 表格,你可以在上面运行as.Date()
    • 查看编辑:您可以只做trunc(dd, "years"),但(奇怪的是)需要转到Datetime,然后再返回Date
    • 我同意 Dirk 并始终建议使用 ISO 8601 格式。它是国际标准,让生活更轻松。见en.wikipedia.org/wiki/ISO_8601
    • 谢谢@tpetzoldt——我刚刚在推特上发布了关于你、我和本的三个不错的答案,并试图“链接”到你但不能:twitter.com/eddelbuettel/status/1394279537215692802。再来一次……
    【解决方案2】:

    如果您只需要年份(而不是对应于一年中第一天的日期),您可以使用lubridate::year()

    df %>% mutate(across(date2,dmy),
                  year_date=year(date2))
    

    如果您确实想要一年的第一天,那么floor_date() 就可以了。

    df %>% mutate(across(date2,dmy),
                   year_date=floor_date(date2,"year"))
    

    或者如果你只需要截断的日期,你可以直接去mutate(year_date=floor_date(dmy(date2)))

    在基础 R 中,year() 将是 format(date2, "%Y"),如@DirkEddelbuettel 的回答所示。

    【讨论】:

    • 嗨,本这个解决方案解决了部分问题,但请注意,使用 year() 时,结果不会返回日期,而是返回 &lt;dbl&gt; 而不是 &lt;date&gt;
    • 是的,这取决于你想要什么。如果(正如我在回答中试图说明的那样)您想要约会,则需要使用floor_date()(如我回答的第二部分和@tpetzoldt 的回答)
    【解决方案3】:

    如果您查阅round_datehelp 页面,您还会看到floor_date

    library("lubridate")
    library("dplyr")
    
    date2 <- c('01/01/2000','08/08/2000','16/03/2001','25/12/2000','29/02/2000')
    name <- c('A','B','C','D','E')
    
    df <- data.frame(date2,name)
    
    df2 <- df %>%
      mutate(date2 = dmy(date2)) %>%
      mutate(year_date = floor_date(date2,'year'))
    
    df2
    

    【讨论】:

    • 您好 tpetzoldt,在这种情况下 floor_date () 总是四舍五入到每年的 1 月 1 日?
    • 查看帮助页面:“floor_date() 采用日期时间对象并将其向下舍入到指定时间单位的最近边界”和:“unit 指定时间单位的字符串或要四舍五入的单位的倍数..."
    猜你喜欢
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多