【问题标题】:Converting a character vector to time and extracting values将字符向量转换为时间并提取值
【发布时间】:2020-12-07 18:00:19
【问题描述】:

嗨,我在使用 R 中的日期时间对象时遇到了一些问题。我有一列实际上只是一个时间列,但是当它被买进 R 时,它被读取为字符向量,但也带有随机日期。解决这个问题的最初想法是首先使用lubridate::mdy_hms() 将该时间列转换为日期时间对象,然后使用strftime()srtptime() 仅提取时间,但我的理解是strptime() 仅适用于字符向量,而@ 987654325@ 适用于 PosiXct 值。我使用 mdy_hms() 函数将字段转换为 PosiXct 对象,然后尝试使用 strftime() 仅提取时间,但它并没有真正起作用。我收到此错误:

Error in as.POSIXlt.default(x, tz = tz) : 
  do not know how to convert 'x' to class “POSIXlt”

我再次尝试了此操作,但使用了 hms 包,但它无法识别我的时间向量中的完整值,并将所有内容转换为 NA 值。这就是为什么我想首先将该字符向量中的所有值转换为日期时间值,然后“丢弃”不正确的日期值。这是我要运行的代码:

library(tidyverse)
library(lubridate)
library(hms)

OM <- read_csv('OM_sightings-1948-2019.csv', na = c("", "NA", "<Null>")) %>%
    #Rename the ID column to OM_ID --> indicates that this entry came from OM database
    rename(OM_ID = ID, Time = Time1, OM_Source = Source) %>% 
    # Drop the Time2, column
    select(-Time2) %>% 
    # Convert 0.0 to NA in both the ActLat and ActLong columns
    mutate_at(vars(ActLat, ActLong), na_if, y = 0)

#Fix the date and time objects in the db
OM_time <- OM %>% 
    mutate(Time = as_hms(Time),
           SightDate = as.Date(mdy_hms(SightDate), tz = "US/Pacific"),
           SightDateTime = mdy_hms(paste(SightDate, Time1), tz = "US/Pacific"))

它运行良好,我可以看到我的“变异”df,但是我收到了这些我理解(大部分)但不确定如何排除故障的警告消息:

Warning messages:
1: Problem with `mutate()` input `Time`.
ℹ Lossy cast from <character> to <hms> at position(s) 58, 60, 61, 62, 63, ... (and 102131 more)
ℹ Input `Time` is `as_hms(Time)`. 
2: Lossy cast from <character> to <hms> at position(s) 58, 60, 61, 62, 63, ... (and 102131 more) 
3: Problem with `mutate()` input `SightDateTime`.
ℹ All formats failed to parse. No formats found.
ℹ Input `SightDateTime` is `mdy_hm(SightDate, tz = "US/Pacific") + Time`. 
4: All formats failed to parse. No formats found. 

这是我的数据的一个示例子集:

structure(list(OM_ID = c(94079, 75473, 95592, 50725, 24689, 73538, 
10246, 107438, 10129, 74301, 107371, 63757, 43427, 93087, 16374, 
28869, 38644, 42348, 89933, 83809, 53855, 96622, 52702, 28263, 
991), SightDate = c("4/22/2015 0:00:00", "7/15/2011 0:00:00", 
"6/30/2015 0:00:00", "6/26/2007 0:00:00", "8/12/2000 0:00:00", 
"6/11/2011 0:00:00", "6/28/1990 0:00:00", "12/7/2018 0:00:00", 
"6/20/1990 0:00:00", "6/26/2011 0:00:00", "12/5/2018 0:00:00", 
"9/1/2009 0:00:00", "8/27/2005 0:00:00", "11/14/2014 0:00:00", 
"6/11/1997 0:00:00", "9/10/2001 0:00:00", "9/8/2004 0:00:00", 
"7/18/2005 0:00:00", "6/25/2014 0:00:00", "8/6/2012 0:00:00", 
"5/16/2008 0:00:00", "7/25/2015 0:00:00", "9/10/2007 0:00:00", 
"8/16/2001 0:00:00", "1/6/1977 0:00:00"), Time = c("12/30/1899 14:00:00", 
"12/30/1899 15:00:00", "12/30/1899 19:21:00", "12/30/1899 9:30:00", 
"12/30/1899 9:30:00", "12/30/1899 12:00:00", "12/30/1899 18:30:00", 
"12/30/1899 13:00:00", "12/30/1899 18:00:00", "12/30/1899 11:52:00", 
"12/30/1899 9:15:00", "12/30/1899 15:33:00", "12/30/1899 9:00:00", 
"12/30/1899 13:48:00", "12/30/1899 15:00:00", "12/30/1899 5:45:00", 
NA, "12/30/1899 16:15:00", "12/30/1899 12:30:00", NA, "12/30/1899 12:00:00", 
"12/30/1899 13:00:00", "12/30/1899 12:30:00", "12/30/1899 8:45:00", 
"12/30/1899 14:15:00"), Month = c(4, 7, 6, 6, 8, 6, 6, 12, 6, 
6, 12, 9, 8, 11, 6, 9, 9, 7, 6, 8, 5, 7, 9, 8, 1), Day = c(22, 
15, 30, 26, 12, 11, 28, 7, 20, 26, 5, 1, 27, 14, 11, 10, 8, 18, 
25, 6, 16, 25, 10, 16, 6), Year = c(2015, 2011, 2015, 2007, 2000, 
2011, 1990, 2018, 1990, 2011, 2018, 2009, 2005, 2014, 1997, 2001, 
2004, 2005, 2014, 2012, 2008, 2015, 2007, 2001, 1977), Pod = c("Orcas", 
"JpLp", "JK", "Orcas", "L", "J", "Orcas", "J", "J", "JK", "J", 
"L12s", "Orcas", "J", "Orcas", "Orcas", "JKL", "J", "J", "J", 
"J", "JKL", "JL", "JL", "Orcas"), LikelyPod = c("Ts", "JKLp", 
"JpKp", NA, NA, "JL53", NA, NA, NA, "JpKp", NA, NA, NA, NA, NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, "SRs"), Direction = c(NA, 
"mill", NA, NA, "E", "SE", "N", "N", "W", NA, "N", "NW", "N", 
NA, "N", NA, "N", "N", "N", "N", "N", "SW", NA, "N", "N"), FishArea = c("17C", 
"7", "7", "7", "19C", "7", "7", "9", "18C", "18C", "11", "7", 
"7", "9", "7", "7", "7", "18C", "7", "7", "18C", "18", "29", 
"7", "10"), Quadrant = c(89, 184, 181, 184, 257, 181, 185, 397, 
151, 152, 420, 185, 181, 387, 169, 181, 181, 162, 176, 170, 163, 
151, 80, 176, 413), Lat = c(48.96, 48.46, 48.5, 48.46, 48.31, 
48.5, 48.44, 47.9, 48.76, 48.74, 47.33, 48.44, 48.5, 48.12, 48.62, 
48.5, 48.5, 48.74, 48.56, 48.65, 48.71, 48.76, 49.01, 48.56, 
47.55), Long = c(-123.73, -123.1, -123.17, -123.1, -123.36, -123.17, 
-123.03, -122.46, -123.02, -123.08, -122.44, -123.03, -123.17, 
-122.71, -123.17, -123.17, -123.17, -123.3, -123.21, -123.24, 
-123.26, -123.02, -123.16, -123.21, -122.41), UTMx = c(446800, 
492000, 487000, 492000, 473400, 487000, 497400, 539100, 497800, 
493500, 540300, 497400, 487000, 520500, 486900, 487000, 487000, 
477600, 484200, 482300, 480700, 497800, 488100, 484200, 542200
), UTMy = c(5423900, 5367800, 5372600, 5367800, 5351700, 5372600, 
5365800, 5305200, 5401200, 5399200, 5242800, 5365800, 5372600, 
5329700, 5386000, 5372600, 5372600, 5399000, 5378600, 5389300, 
5395300, 5401200, 5428700, 5378600, 5266600), OM_Source = c("TWM-SA-Pub", 
"TWM-SW", "TWM-HYD-Rel", "TWM-Pager", "TWM-Pager", "TWM-SW", 
"TWM-SA-Rel", "TWM-SA-Rel", "TWM-SA-Rel", "SPOT", "TWM-SA-Pub", 
"SPOT", "TWM-Pager", "TWM-HYD-Rel", "TWM-Pager", "TWM-SA-Pub", 
"TWM-SA-Rel", "TWM-Pager", "TWM-SW", "BCCSN", "TWM-SW", "Soundwatch", 
"BCCSN", "TWM-Pager", "TWM-SA-Rel"), ActLat = c(NA, 48.452, NA, 
NA, NA, 48.488, NA, NA, NA, 48.7667, NA, 48.4585, NA, NA, NA, 
NA, NA, NA, 48.5385, 48.682, 48.738, 48.7876, 49.0108, NA, NA
), ActLong = c(NA, -123.0777, NA, NA, NA, -123.1233, NA, NA, 
NA, -123.0776, NA, -123.065, NA, NA, NA, NA, NA, NA, -123.1725, 
-123.251, -123.253, -123.0389, -123.1659, NA, NA)), row.names = c(NA, 
-25L), class = c("tbl_df", "tbl", "data.frame"))

感谢您的帮助!我是新手/自学成才,我很难理解处理时间数据的最佳方式。

【问题讨论】:

  • 这归结为时代所代表的。如果它们是一天中的时间,您最好将它们存储为日期时间并仅打印时间部分。如果它们是持续时间,您可以选择将它们存储为整数秒或分钟,或使用来自 lubridate 的 duration 之类的东西。
  • 在您讨论过的一些处理之后,您已经与“tz”列共享了您的数据。在转换时间之前发布流程早期步骤的示例数据可能会更有帮助。
  • 对不起,我没有意识到这一点!我刚刚更新了我的子集的dput()。请让我知道这是否可行!
  • @AllanCameron 很抱歉不清楚,我正在尝试将这些数据存储为一天中的时间对象。不是持续时间。老实说,我对如何导入这些数据感到非常恼火,因为在原始数据库中,时间列中没有附加日期,我认为这是跨不同平台导出和导入的人工制品。

标签: r date dplyr lubridate


【解决方案1】:

日期和时间在 R 中可能非常棘手,因为它可以有很多不同的表示方式。 lubridate 没有一个只是时间的类,但是相关的包hms 增加了一个时间类,可以让它变得更简单。

我经常发现同时拥有日期和日期/时间列很有帮助,这样您就可以使用最有意义的部分。
对于示例数据,使用 lubridate::mdy_hms(SighDate) 将其转换为午夜的日期。 hms::as_hms(Time) 为我工作。然后将两者添加到在 date_time 列中创建,然后将 Date 转换为日期类(如果需要进行分析)。下面我为时间创建了一个新列,以跟踪它在做什么,但往往会替换时间列。

library(lubridate)
library(hms)
library(tidyverse)
# OM = your data provided above 

OM2 <- OM %>%
      mutate(SightDate = mdy_hms(SightDate, tz = "America/Los_Angeles"),
             Time2 = as_hms(mdy_hms(Time)),
             Date_time = SightDate+Time2,
             SightDate = as.Date(SightDate)
             )

OM2 %>%
      select(OM_ID, SightDate, Time, Time2, Date_time, everything())

# # A tibble: 25 x 20
# OM_ID SightDate  Time  Time2 Date_time           Month   Day  Year Pod   LikelyPod Direction FishArea Quadrant   Lat
# <dbl> <date>     <chr> <tim> <dttm>              <dbl> <dbl> <dbl> <chr> <chr>     <chr>     <chr>       <dbl> <dbl>
#       1  94079 2015-04-22 12/3~ 14:00 2015-04-22 14:00:00     4    22  2015 Orcas Ts        NA        17C            89  49.0
# 2  75473 2011-07-15 12/3~ 15:00 2011-07-15 15:00:00     7    15  2011 JpLp  JKLp      mill      7             184  48.5
# 3  95592 2015-06-30 12/3~ 19:21 2015-06-30 19:21:00     6    30  2015 JK    JpKp      NA        7             181  48.5
# 4  50725 2007-06-26 12/3~ 09:30 2007-06-26 09:30:00     6    26  2007 Orcas NA        NA        7             184  48.5
# 5  24689 2000-08-12 12/3~ 09:30 2000-08-12 09:30:00     8    12  2000 L     NA        E         19C           257  48.3
# 6  73538 2011-06-11 12/3~ 12:00 2011-06-11 12:00:00     6    11  2011 J     JL53      SE        7             181  48.5
# 7  10246 1990-06-28 12/3~ 18:30 1990-06-28 18:30:00     6    28  1990 Orcas NA        N         7             185  48.4
# 8 107438 2018-12-07 12/3~ 13:00 2018-12-07 13:00:00    12     7  2018 J     NA        N         9             397  47.9
# 9  10129 1990-06-20 12/3~ 18:00 1990-06-20 18:00:00     6    20  1990 J     NA        W         18C           151  48.8
# 10  74301 2011-06-26 12/3~ 11:52 2011-06-26 11:52:00     6    26  2011 JK    JpKp      NA        18C           152  48.7
# # ... with 15 more rows, and 6 more variables: Long <dbl>, UTMx <dbl>, UTMy <dbl>, OM_Source <chr>, ActLat <dbl>,
# #   ActLong <dbl>

我很确定 Access 将日期和时间表示为表示自某个起源以来的时间量的数值。看起来使用的原点是 1899 年 12 月 30 日,它显示在您的时间列中。当您从 Access 导出到 csv 时,您还可以查看您的设置。我对 excel 比较熟悉,但我认为他们的设置类似,因此您可以在导入之前操作格式。

【讨论】:

  • 谢谢!所以是的,我不想提供太多细节,以免让我的帖子混乱,但是是的。我有一个包含真实日期的日期列,而时间列(在 Access 中)仅显示 24 小时格式的时间。但是,当导入 R 时,它会附加一个随机日期。使用 hms::as_hms 调用会做我担心的事情,并删除时间向量的所有内容,而是用 NA 值填充它。我将更新我的 OP 以反映更好的问题、代码和示例数据。非常感谢您的帮助!
  • 我更新了新的样本数据。使用您提供的 as_hms 示例工作正常,但如果它返回 NA,则可能是由您发布的子集之外的东西引起的。
  • 我认为您的错误来自对具有日期组件和时间组件的数据使用 as_hms。您可以先使用 mdy_hms() 转换为 POSIXct,也可以在将字符转换为时间之前去掉无意义的日期部分。
  • 是的!那行得通,谢谢!但是,当我有NA 时间值时,它们仍会填充到 SightDateTime 列,即(1/1/2010 NA),但我希望如果时间有 NA,它不会被附加到 SightDateTime。我仍然在我的 df 末尾添加了一个“tz”列,而这在过去没有发生过,我不知道为什么?这是我最终运行的代码:OM_time &lt;- OM %&gt;% mutate(Time = as_hms(mdy_hms(Time)), SightDate = as.Date(mdy_hms(SightDate), tz = "US/Pacific"), SightDateTime = paste(SightDate, Time), tz = "US/Pacific")
  • 您在上面的代码中创建了 tz 列,我认为它应该在 mdy_hms 的括号内。
猜你喜欢
  • 2020-12-14
  • 1970-01-01
  • 2017-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多