【问题标题】:Can I apply a function over a vector using base tryCatch?我可以使用基本 tryCatch 在向量上应用函数吗?
【发布时间】:2020-03-18 22:00:19
【问题描述】:

我正在尝试从具有混合日期格式的向量中解析日期(使用 lubridate 函数)。

departureDate <- c("Aug 17, 2020 12:00:00 AM", "Nov 19, 2019 12:00:00 AM", "Dec 21, 2020 12:00:00 AM",
"Dec 24, 2020 12:00:00 AM", "Dec 24, 2020 12:00:00 AM", "Apr 19, 2020 12:00:00 AM", "28/06/2019",
"16/08/2019", "04/02/2019", "10/04/2019", "28/07/2019", "26/07/2019", 
"Jun 22, 2020 12:00:00 AM", "Apr 5, 2020 12:00:00 AM",  "May 1, 2021 12:00:00 AM")

一开始我没有注意到,我尝试使用lubridate::mdy_hms(departureDate) 进行解析,结果NA 的日期值与解析器的格式不同。 由于格式可能会随矢量的随机位置而改变,我尝试使用以下句子:

departureDate <- tryCatch(mdy_hms(departureDate), 
                             warning = function(w){return(dmy(departureDate))})

这带来了更多的NA,因为它只应用了警告函数调用。有没有办法使用我的方法来解决这个问题?

提前致谢

【问题讨论】:

    标签: r try-catch


    【解决方案1】:

    我们可以使用lubridate::parse_date_time,它可以采用多种格式。

    lubridate::parse_date_time(departureDate, c('%b %d, %Y %I:%M:%S %p', '%d/%m/%Y'))
    
    #[1] "2020-08-17 UTC" "2019-11-19 UTC" "2020-12-21 UTC" "2020-12-24 UTC"
    #[5] "2020-12-24 UTC" "2020-04-19 UTC" "2019-06-28 UTC" "2019-08-16 UTC"
    #[9] "2019-02-04 UTC" "2019-04-10 UTC" "2019-07-28 UTC" "2019-07-26 UTC"
    #[13] "2020-06-22 UTC" "2020-04-05 UTC" "2021-05-01 UTC"
    

    由于departureDate 中的月份名称是英文,因此您还需要将语言环境设置为英文。

    如果您有非英语语言环境,请参考How to change the locale of R?

    【讨论】:

    • 我怀疑用户也会遇到问题,如果他们仍然有语言环境问题(请参阅我的答案中的 cmets),因为这是使用相同的 %b%p 语言环境-具体参数。 (或者也许不是。)
    • 是的,如果 OP 具​​有非英语语言环境,这将不起作用。更新了答案以提及这一点。
    【解决方案2】:

    理想的情况是代码应该能够自己处理每种格式,而不会让它陷入异常。

    另一个需要考虑的问题是 myd_hms() 函数返回 POSIXct 数据类型的日期,而 dmy() 返回 Date 类型,因此它们不能很好地混合在一起。

    下面的代码应用 mdy_hms(),然后将其转换为 Date。然后它测试 NA 并将第二个函数 dmy() 应用于缺失值。如果要识别更多格式,可以在管道中随意添加更多规则。

    library(dplyr)
    
    dates.converted <- 
      mdy_hms(departureDate, tz = ) %>% 
      as.Date() %>%
      ifelse(!is.na(.), ., dmy(departureDate)) %>%
      structure(class = "Date")
    
    print(dates.converted)
    

    输出

     [1] "2020-08-17" "2019-11-19" "2020-12-21" "2020-12-24" "2020-12-24" "2020-04-19" "2019-06-28" "2019-08-16"
     [9] "2019-02-04" "2019-04-10" "2019-07-28" "2019-07-26" "2020-06-22" "2020-04-05" "2021-05-01"
    

    【讨论】:

      【解决方案3】:

      一种方法是遍历候选格式列表并将其仅应用于以前未正确解析的日期。

      fmts <- c("%b %d, %Y %H:%M:%S %p", "%d/%m/%Y")
      dates <- rep(Sys.time()[NA], length(departureDate))
      for (fmt in fmts) {
        isna <- is.na(dates)
        if (!any(isna)) break
        dates[isna] <- as.POSIXct(departureDate[isna], format = fmt)
      }
      dates
      #  [1] "2020-08-17 12:00:00 PDT" "2019-11-19 12:00:00 PST" "2020-12-21 12:00:00 PST"
      #  [4] "2020-12-24 12:00:00 PST" "2020-12-24 12:00:00 PST" "2020-04-19 12:00:00 PDT"
      #  [7] "2019-06-28 00:00:00 PDT" "2019-08-16 00:00:00 PDT" "2019-02-04 00:00:00 PST"
      # [10] "2019-04-10 00:00:00 PDT" "2019-07-28 00:00:00 PDT" "2019-07-26 00:00:00 PDT"
      # [13] "2020-06-22 12:00:00 PDT" "2020-04-05 12:00:00 PDT" "2021-05-01 12:00:00 PDT"
      as.Date(dates)
      #  [1] "2020-08-17" "2019-11-19" "2020-12-21" "2020-12-24" "2020-12-24" "2020-04-19" "2019-06-28"
      #  [8] "2019-08-16" "2019-02-04" "2019-04-10" "2019-07-28" "2019-07-26" "2020-06-22" "2020-04-05"
      # [15] "2021-05-01"
      

      我鼓励您将最可能的格式放在首位 fmts 向量中。

      这种设置方式,一旦正确找到所有元素,就不会尝试其他格式(即break)。


      编辑:如果在本地无法识别AM/PM 的 LOCALE 中存在差异,那么一种方法是首先将它们从字符串中删除:

      departureDate <- gsub("\\s[AP]M$", "", departureDate)
      departureDate
      #  [1] "Aug 17, 2020 12:00:00" "Nov 19, 2019 12:00:00" "Dec 21, 2020 12:00:00"
      #  [4] "Dec 24, 2020 12:00:00" "Dec 24, 2020 12:00:00" "Apr 19, 2020 12:00:00"
      #  [7] "28/06/2019"            "16/08/2019"            "04/02/2019"           
      # [10] "10/04/2019"            "28/07/2019"            "26/07/2019"           
      # [13] "Jun 22, 2020 12:00:00" "Apr 5, 2020 12:00:00"  "May 1, 2021 12:00:00" 
      

      然后使用更简单的格式:

      fmts <- c("%b %d, %Y %H:%M:%S", "%d/%m/%Y")
      

      【讨论】:

      • 我可以改用 lubridate 函数吗?
      • 当然。将as.POSIXct 替换为lubridate::as_datetime,它的工作原理完全相同(尽管速度更快)。
      • 问题是,我需要解析日期,无法在有效日期获得NA's
      • 哦,我明白了……如果是约会,你想要一个Date;如果是时间戳,你要POSIXct,是吗?
      • 不...我只需要日期为Date。尝试了您的后一个建议...不适用于lubridate
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-20
      • 1970-01-01
      相关资源
      最近更新 更多