【问题标题】:R datetime series missing valuesR日期时间序列缺失值
【发布时间】:2022-01-15 03:22:55
【问题描述】:

我正在从 chr 转换为 POSIXct 格式为“%Y-%m-%d %H:%M:%S 但是,数据集中的某些时间没有秒部分 (%S) 所以当我将没有秒数的时间转换为 DateTime 作为空单元格返回 - NA 我如何确保不会发生这种情况。无论是否缺少某些时间部分,我都希望它们全部返回为 DateTime?

这种格式的日期时间 ("%Y-%m-%d %H:%M:%S") 正确返回为 POSIXct

但是这种格式的日期时间(“%Y-%m-%d %H:%M”)返回为 NA

这是用于转换的代码 trips$ended_at <- as.POSIXct(trips$ended_at, format = "%Y-%m-%d %H:%M:%S") 这是一个包含超过一百万个条目的巨大数据集,所以我什至不知道哪些日期时间没有秒部分。 有没有办法让那些没有秒部分的人只能有零和结尾? 例如,2020-29-04 01:57 转换为 POSIXct 时将返回为 2020-29-04 01:57:00

请帮忙!

【问题讨论】:

  • 是否总是缺少秒数和仅秒数,或者是否存在分钟/小时等丢失的情况?例如2020/01/18 15:NA:12 或 2020/01/18 15
  • 我觉得奇怪的是,您以 "29/04/2020" 的格式显示日期,然后说 "%Y-%m-%d" 有效。
  • @rg255 是的,总是缺少几秒钟
  • 是的,我的错我会编辑 @r2evans
  • 我看到您的编辑,谢谢,但是..."2020/29/04" != "%Y-%m-%d",问题示例仍然与您对有效方法的断言不一致。无论如何,我的答案(方法 2)中的代码将直接处理其中任何一种格式。

标签: r datetime date-formatting posixct


【解决方案1】:

两种方法:

  1. 将文字 :00 连接到只有小时/分钟的时间戳的末尾:

    as.POSIXct(trips$ended_at, format = "%Y-%m-%d %H:%M:%S")
    # [1] "2020-04-29 01:57:00 EDT" "2020-04-29 01:57:00 EDT"
    # [3] "2020-04-29 01:57:00 EDT" NA                       
    # [5] "2020-04-29 01:57:00 EDT"
    
    gsub("( [0-9]+:[0-9]+)$", "\\1:00", trips$ended_at)
    # [1] "2020-04-29 01:57:00" "2020-04-29 01:57:00" "2020-04-29 01:57:00"
    # [4] "2020-04-29 01:57:00" "2020-04-29 01:57:00"
    
    as.POSIXct(gsub("( [0-9]+:[0-9]+)$", "\\1:00", trips$ended_at), format = "%Y-%m-%d %H:%M:%S")
    # [1] "2020-04-29 01:57:00 EDT" "2020-04-29 01:57:00 EDT"
    # [3] "2020-04-29 01:57:00 EDT" "2020-04-29 01:57:00 EDT"
    # [5] "2020-04-29 01:57:00 EDT"
    
  2. 如果您需要尝试多种“候选”格式,则可以迭代地逐步完成它们。此循环遍历格式,将最有可能的候选者放在首位。如果在任何时候所有时间戳都已转换,它会提前退出for 循环。

    candidates <- c("%Y-%m-%d %H:%M", "%d/%m/%Y %H:%M:%S", "%d/%m/%Y %H:%M")
    out <- as.POSIXct(trips$ended_at, format = "%Y-%m-%d %H:%M:%S")
    for (fmt in candidates) {
      if (!length(isna <- is.na(out))) break
      out[isna] <- as.POSIXct(trips$ended_at[isna], format = fmt)
    }
    out
    # [1] "2020-04-29 01:57:00 EDT" "2020-04-29 01:57:00 EDT"
    # [3] "2020-04-29 01:57:00 EDT" "2020-04-29 01:57:00 EDT"
    # [5] "2020-04-29 01:57:00 EDT"
    

数据

trips <- data.frame(ended_at = c("2020-04-29 01:57:00", "2020-04-29 01:57:00", "2020-04-29 01:57:00", "2020-04-29 01:57", "2020-04-29 01:57:00"))

【讨论】:

    【解决方案2】:

    这是我通常做的事情。通过nchar()检查POSIXct格式化前的字符串长度,将结果存入新列,例如:

    trips$check&lt;-nchar(trips$ended_at)

    然后检查所有trips$ended_at 的长度是否相同,并为那些没有的添加缺少的秒数:

    trips$ended_at_new&lt;-ifelse(trips$check==19,trips$ended_at,paste(trips$ended_at,":00",sep=""))

    您可以将 19 换成您使用的任何日期时间格式。重要提示:这仅适用于时间戳末尾缺少秒数的情况,而不是时间戳因任何其他原因少于 19 个字符的情况。

    【讨论】:

    • nchar 是一个很好的尝试,但它确实遇到了一个小问题:如果天或月是个位数而不是 0 填充,那么它会缩短字符串的总长度。例如,as.POSIXct("29/4/2020 5:00:00", format = "%d/%m/%Y %H:%M:%S") 可以正常工作,但与您的 ifelse 一起使用时,它会将 :00 附加到字符串中。
    • 好点。不过,它应该在这种情况下工作,因为海报的示例显示 0-padding。对于一般用途,您的解决方案更优雅。感谢您的启发!
    【解决方案3】:

    这是我采用的方法,在假设您正在处理两种可能性的情况下使用 ifelse() - 有和没有秒

    date_time <- c("2020-01-18 20:12:16", "2020-01-18 20:12")
    
    ifelse(nchar(date_time) == 16, 
           format(as.POSIXct(date_time, format="%Y-%m-%d %H:%M"), "%Y-%m-%d %H:%M:%S"), 
           format(as.POSIXct(date_time, format="%Y-%m-%d %H:%M:%S"), "%Y-%m-%d %H:%M:%S"))
    

    【讨论】:

    • 看我下面的commentnchar在这里面的使用;受制于日、月和小时的个位数(数据中不常见的故障)。
    • 另外两件事:(1)您可以通过ifelse-ing 仅格式本身来提高效率,因此ifelse(..., "%Y..%S", "%Y..%M"),并将format(as.POSIXct(date_time, ..)) 移出 ifelse。在当前情况下,format(as.POSIXct 的调用次数是需要的两倍。 (2) format(.) 打破这个并返回一个字符串而不是 POSIXt-class 对象。我建议只是as.POSIXct(date_time, format = ifelse(==,"",""))。
    猜你喜欢
    • 2016-03-28
    • 2011-04-03
    • 2016-12-08
    • 1970-01-01
    • 1970-01-01
    • 2018-05-14
    • 2016-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多