R извлекает компоненты времени из полустандартных строк
Настроить
У меня есть столбец длительностей, хранящихся в виде строк в кадре данных. Я хочу преобразовать их в соответствующий объект времени, вероятно, POSIXlt. Большинство строк легко разобрать, используя этот метод:
> data <- data.frame(time.string = c(
+ "1 d 2 h 3 m 4 s",
+ "10 d 20 h 30 m 40 s",
+ "--"))
> data$time.span <- strptime(data$time.string, "%j d %H h %M m %S s")
> data$time.span
[1] "2012-01-01 02:03:04" "2012-01-10 20:30:40" NA
Отсутствующие длительности закодированы "--"
и должны быть преобразованы в NA
- это уже происходит, но должно быть сохранено.
Сложность состоит в том, что в строку сбрасываются элементы с нулевым значением Таким образом, желаемое значение 2012-01-01 02:00:14
будет строка "1 d 2 h 14 s"
, Однако эта строка анализирует NA
с простым парсером:
> data2 <- data.frame(time.string = c(
+ "1 d 2 h 14 s",
+ "10 d 20 h 30 m 40 s",
+ "--"))
> data2$time.span <- strptime(data2$time.string, "%j d %H h %M m %S s")
> data2$time.span
[1] NA "2012-01-10 20:30:40" NA
Вопросы
- Что такое "путь R" для обработки всех возможных форматов строк? Может быть, проверить и извлечь каждый элемент в отдельности, а затем рекомбинировать?
- Является ли POSIXlt правильным целевым классом? Мне нужно, чтобы продолжительность была свободна от любого конкретного времени начала, поэтому добавление ложных данных года и месяца (
2012-01-
) тревожит.
Решение
У @mplourde определенно была правильная идея с динамическим созданием строки форматирования, основанной на тестировании различных условий в формате даты. Добавление cut(Sys.Date(), breaks='years')
в качестве базовой линии для datediff
было также хорошо, но не смог объяснить критическую причину в as.POSIXct()
Примечание: я использую базу R2.11, возможно, это было исправлено в более поздних версиях.
Выход из as.POSIXct()
резко меняется в зависимости от того, включен ли компонент даты:
> x <- "1 d 1 h 14 m 1 s"
> y <- "1 h 14 m 1 s" # Same string, no date component
> format (x) # as specified below
[1] "%j d %H h %M m %S s"
> format (y)
[1] "% H h % M %S s"
> as.POSIXct(x,format=format) # Including the date baselines at year start
[1] "2012-01-01 01:14:01 EST"
> as.POSIXct(y,format=format) # Excluding the date baselines at today start
[1] "2012-06-26 01:14:01 EDT"
Таким образом, второй аргумент в пользу difftime
функция должна быть:
- Начало первого дня текущего года, если во входной строке есть компонент дня
- Начало текущего дня, если во входной строке нет компонента дня
Это может быть достигнуто путем изменения параметра устройства на cut
функция:
parse.time <- function (x) {
x <- as.character (x)
break.unit <- ifelse(grepl("d",x),"years","days") # chooses cut() unit
format <- paste(c(if (grepl("d", x)) "%j d",
if (grepl("h", x)) "%H h",
if (grepl("m", x)) "%M m",
if (grepl("s", x)) "%S s"), collapse=" ")
if (nchar(format) > 0) {
difftime(as.POSIXct(x, format=format),
cut(Sys.Date(), breaks=break.unit),
units="hours")
} else {NA}
}
2 ответа
difftime
объекты являются объектами длительности времени, которые могут быть добавлены к POSIXct
или же POSIXlt
объекты. Может быть, вы хотите использовать это вместо POSIXlt
?
Что касается преобразования из строк во временные объекты, вы можете сделать что-то вроде этого:
data <- data.frame(time.string = c(
"1 d 1 h",
"30 m 10 s",
"1 d 2 h 3 m 4 s",
"2 h 3 m 4 s",
"10 d 20 h 30 m 40 s",
"--"))
f <- function(x) {
x <- as.character(x)
format <- paste(c(if (grepl('d', x)) '%j d',
if (grepl('h', x)) '%H h',
if (grepl('m', x)) '%M m',
if (grepl('s', x)) '%S s'), collapse=' ')
if (nchar(format) > 0) {
if (grepl('%j d', format)) {
# '%j 1' is day 0. We add a day so that x = '1 d' means 24hrs.
difftime(as.POSIXct(x, format=format) + as.difftime(1, units='days'),
cut(Sys.Date(), breaks='years'),
units='hours')
} else {
as.difftime(x, format, units='hours')
}
} else { NA }
}
data$time.span <- sapply(data$time.string, FUN=f)
Я думаю вам повезет больше с lubridate
Из дат и времен Made Easy с lubridate:
5.3. Длительности
...
Продолжительность продолжительности не зависит от високосных лет, високосных секунд и летнего времени, поскольку длительности измеряются в секундах. Следовательно, длительности имеют постоянные длины и могут быть легко сопоставлены с другими длительностями. Длительности являются подходящим объектом для использования при сравнении атрибутов, основанных на времени, таких как скорости, скорости и время жизни. lubridate использует класс difftime из базы R для продолжительности. Для этого были созданы дополнительные методы difftime.
lubridate использует класс difftime из базы R для продолжительности. Для этого были созданы дополнительные методы difftime.
...
Объекты длительности могут быть легко созданы с помощью вспомогательных функций dyears(), dweeks(), ddays(), dhours(), dminutes() и dseconds(). Символ d в заголовке обозначает продолжительность и отличает эти объекты от объектов периода, которые обсуждаются в разделе 5.4. Каждый объект создает длительность в секундах, используя оценочные отношения, приведенные выше.
Тем не менее, я (пока) не нашел функцию для разбора строки по длительности.
Вы также можете взглянуть на Ruby's Chronic, чтобы увидеть, насколько элегантным может быть анализ времени. Я не нашел подобную библиотеку для R.