【问题标题】:different format of time - how to read it in? R, readr不同的时间格式 - 如何读取它? R,读者
【发布时间】:2018-02-22 21:24:24
【问题描述】:

我有一个文件,其中包含记录事件时间的列。有时时间采用 mm:ss 格式,有时末尾有额外的零 - mm:ss:00。请参见下面的示例:

id    time
1     20:50
2     76:58:00
3     56:13:00
4     03:44

当我使用 read_csv 读取此数据时,所有较短格式 (mm:ss) 的值都标记为 NA。当我使用read_csv('data.csv', col_types = cols(time = col_character())) 将此值设置为作为字符串读取时,所有值都更改为更短的格式(所以我在第二行中有76:58)。如何解析此 time 列以将所有数据都采用一种格式(无论是较短还是较长),但作为 time 类型的变量并且不会丢失这些较短格式的输入的数据?

为什么在解析为时间时将所有 8 个字符的值都替换为“NA”?

【问题讨论】:

  • 我没有read_csv 使用您的示例数据的问题。这表明问题在于您的文件data.csv

标签: r parsing readr


【解决方案1】:

解决第一个问题(短/长格式):假设time 的所有值都是 5 个字符 (MM:SS) 或 8 个字符 (MM:SS:00),您可以转换为短格式像这样,假设数据框被命名为df1:

library(dplyr)
df1 %>% 
  mutate(time = substring(time, 1, 5)) 

  id   time
1  1  20:50
2  2  76:58
3  3  56:13
4  4  03:44

这种格式允许我们使用来自lubridate 包的ms 函数。请注意,您的值不是时间(如时钟上的时间)- 它们是持续时间。因此,您可以像这样转换为 Period 对象:

library(lubridate)
df1 %>% 
  mutate(time = substring(time, 1, 5), 
         ts   = ms(time))

  id  time      ts
1  1 20:50 20M 50S
2  2 76:58 76M 58S
3  3 56:13 56M 13S
4  4 03:44  3M 44S

lubridate 也有一个duration 函数,它需要更多的短格式格式(添加“M”和“S”)。

【讨论】:

  • 第一部分不适用于我的情况,因为当我使用 read_csv('data.csv', col_types = cols(time = col_character())) 解析为字符时,我已经有了较短的(5 个字符)格式。第二个有助于表示值,但由于我进一步需要对它们进行排序,所以在我的情况下它是相当无用的(arrange() 似乎不适用于ms() 格式化的值。所以基本上,我认为我需要什么实现的方法是将这些值保持为time而不获取NAs。实际上,你知道为什么精确解析为time会用NA替换8个字符的值吗?
  • 我无法重现您的任何一个问题。使用您的 read_csv 命令,我在 tibble 中同时获得了 5 和 8 字符格式。我可以安排或排序 Period 对象。我认为您的数据一定存在一些问题,这在您的示例中并不明显。
  • x <- tribble( ~id, ~time, 1, "20:50", 2, "76:58:00", 3, "56:13:00", 4, "03:44" ) x <- x %>% mutate(time = substr(time, 1, 5), time2 = ms(time)) x %>% arrange(time2) 这似乎以秒为单位排列周期值。如何将其更改为先按分钟排序,然后按秒排序?
  • 似乎确实存在使用 tibbles 或 tribbles 的问题,而不是数据帧(我最初使用的)。不过现在是周末,我下周去看看:)
【解决方案2】:

接下来呢?

as.ms <- function(x) {
    unlist(lapply(sapply(x, function(w)
        strsplit(as.character(w), ":")), function(w) {
            if (length(w) == 2) {
                w[2] <- sprintf("%s.00", w[2])
            } else {
                w[2] <- sprintf("%4.2f", as.numeric(w[2]) + as.numeric(w[3]) / 1000);
            }
            w <- paste0(w[1:2], collapse = ":");
        }
    ))
}


lubridate::ms(as.ms(df$time));
#[1] "20M 50S" "76M 58S" "56M 13S" "3M 44S"

解释:as.ms 必要时添加小数秒;那么你可以使用lubridate::hms 来解析时间。

如果你有毫秒,这个方法也可以工作。例如,考虑

df2 <- read.table(text =
    "id    time
1     20:50
2     76:58:00
3     56:13:250
4     03:44", header = T);

然后

lubridate::ms(as.ms(df2$time));
#[1] "20M 50S"    "76M 58S"    "56M 13.25S" "3M 44S"

样本数据

df <- read.table(text =
    "id    time
1     20:50
2     76:58:00
3     56:13:00
4     03:44", header = T);

【讨论】:

  • 值是 MM::SS 或 MM::SS::00,而不是 HH::MM::SS。
  • 该死的;读得不够仔细。好的,感谢@neilfws 指出这一点。我会尽快删除它。
  • 现在应该修复了。我进行了更改,使其也可以处理毫秒,例如“时间 = 56:13:250”。
  • @MauritsEvers 不幸的是,在我的情况下,使用ms 函数不是一个选项,因为我需要进一步对这些值进行排序,arrange 似乎不适用于持续时间对象。还是我错了?
  • @jakes arrange 应该可以与 time@dates 一起正常工作。不确定您认为问题是什么。
猜你喜欢
  • 2021-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-06
  • 2013-05-08
  • 2019-03-16
  • 2020-02-23
  • 1970-01-01
相关资源
最近更新 更多