Я пытаюсь создать столбец данных, в котором будет указан только час каждого наблюдения, на основе данных времени, отформатированных как ЧЧ:ММ:СС в R.
Я хочу сделать это, чтобы можно было группировать наблюдения в моем наборе данных по часам, когда они происходили.
Пример вектора времени: a <- c(22:00:03, 22:00:05, 22:00:07, 22:00:09)
Желаемый результат: [1] 22 22 22 22
Мой набор данных очень велик, поэтому создание отдельных векторов с почасовыми наблюдениями требует много времени.
Я пытался изучить функцию «смазка», но не нашел решения.
Любая помощь приветствуется!
Вы получите больше помощи, если опубликуете воспроизводимый пример и ожидаемый результат.
substr(a, 1, 2)
library(readr) parse_number(a)
library(data.table); hour(as.ITime(a))
library(lubridate) a <- hms(a) hour(a)
Если вы используете пакет lubridate для анализа дат. Вы можете использовать lubridate::hour
, чтобы узнать часы. Нравится: x <- lubridate::hms( c("22:00:03", "22:00:05", "22:00:07", "22:00:09")) %>% lubridate::hour()
Вы можете использовать регулярное выражение, чтобы получить первые две цифры:
as.numeric(gsub("(^\\d{2}).*", "\\1", a))
# [1] 22 22 22 22
Преобразуйте его в POSIXlt, а затем отформатируйте, чтобы извлечь час:
as.numeric(format(strptime(a, "%H:%M"), "%H"))
# [1] 22 22 22 22
В lubridate вы можете преобразовать его с помощью hms()
, который преобразует вектор символов в формате HH:MM
в объект точки, а затем извлекает компонент часа:
library(lubridate)
hour(hms(a))
# [1] 22 22 22 22
Пакет dttr2
имеет аналогичный синтаксис для смазки:
library(dttr2)
dtt_hour(dtt_time(a))
# [1] 22 22 22 22
Разделите его на :
и возьмите первый элемент:
as.numeric(sapply(strsplit(a, ":", fixed = TRUE), `[[`, 1))
# [1] 22 22 22 22
stringr
реализовано str_split_i()
в версии пакета 1.5.0, что позволяет разбивать и выбирать элемент по индексу:
library(stringr)
as.numeric(str_split_i(a, ":", 1))
# [1] 22 22 22 22
Пакет strex
может упростить использование общих регулярных выражений для извлечения всего, что происходит до первого совпадения с шаблоном:
library(strex)
as.numeric(str_before_first(a, ":"))
# [1] 22 22 22 22
Используйте пакет datetime
, чтобы превратить его в объект времени, преобразовать его в числовое значение (которое вернет секунды) и преобразовать в часы:
library(datetime)
as.numeric(as.time(a)) / (60 * 60)
# [1] 22 22 22 22
Я использовал вторую функцию, используя as.numeric, format и strptime, и это сработало отлично.
Попробуйте sub
a <- c("22:00:03", "22:00:05", "22:00:07", "22:00:09")
sub <- as.numeric(sub(":.*", "", a))
## [1] 22 22 22 22
Сравнивая это с опубликованными (плюс решениями difftime и chron) в порядке медианного времени (сначала самое быстрое), substr был самым быстрым, но решения substr и gsub предполагают нулевой заполненный час, тогда как другие решения, которые решают общую проблему, этого не делают. допускает ненулевой заполненный час, суб-самый быстрый. Все три самых быстрых общих решения являются базовыми. Решения chron и dttr2 кажутся наиболее читабельными или, возможно, смазывающими, в зависимости от того, считаете ли вы, что time или hms более читабельны.
library(lubridate)
library(dttr2)
library(strex)
library(datetime)
library(chron)
library(microbenchmark)
a <- c("22:00:03", "22:00:05", "22:00:07", "22:00:09")
microbenchmark(
substr = substr(a, 1, 2), # assumes 0-filled hour
sub = as.numeric(sub(":.*", "", a)),
gsub = as.numeric(gsub("(^\\d{2}).*", "\\1", a)), # assumes 0-filled hour
strsplit = as.numeric(sapply(strsplit(a, ":", fixed = TRUE), `[[`, 1)),
POSIXlt = as.numeric(format(strptime(a, "%H:%M"), "%H")),
datetime = as.numeric(as.time(a)) / (60 * 60),
difftime = as.integer(as.difftime(a), unit = "hour"),
chron = chron::hours(times(a)),
strex = as.numeric(str_before_first(a, ":")),
lubridate = lubridate::hour(hms(a)),
dttr2 = dtt_hour(dtt_time(a))
)
предоставление
Unit: microseconds
expr min lq mean median uq max neval
substr 4.4 7.90 8.957 8.90 10.20 19.4 100
sub 37.5 45.90 53.228 51.40 60.60 91.9 100
gsub 56.1 71.35 81.032 78.95 90.60 147.5 100
strsplit 73.4 89.70 98.007 100.80 103.30 150.6 100
POSIXlt 133.8 148.80 164.063 165.20 177.00 214.9 100
datetime 193.1 219.90 245.828 233.05 258.50 433.0 100
difftime 290.9 325.35 357.287 354.55 374.75 613.5 100
chron 291.1 320.50 357.119 367.05 379.15 573.7 100
strex 742.2 815.10 916.158 921.70 953.60 1602.0 100
lubridate 1007.9 1100.60 1262.641 1176.25 1225.85 7782.4 100
dttr2 8321.5 8574.90 8841.866 8724.10 8897.80 13899.2 100
Можно добавить as.numeric(substr(a, 1, 2))
, это быстрее на порядок. Предполагая, что часы имеют две цифры, как обычно и должно быть.
Добавили, но это предполагает нулевой заполненный час, тогда как другие (кроме gsub) этого не делают, поэтому sub по-прежнему остается самым быстрым из общих решений.
Пожалуйста, прочитайте о как создать отличный воспроизводимый пример R и соответствующим образом обновите свой вопрос. Включите образец ваших данных, вставив вывод
dput(<your data frame>)
в свое сообщение илиdput(head(<your data frame>))
, если у вас большой фрейм данных. Если вы не можете опубликовать свои данные, укажите код для создания репрезентативных данных. Также укажите код, который вы пробовали, все соответствующие ошибки и ожидаемый результат.