tl; dr : как преобразовать "30.10.2015 09:00:00" в "0900" с помощью sub?

У меня есть следующий фрейм данных df (dput в конце вопроса):

str(df)
'data.frame':   75 obs. of  2 variables:
 $ V1: chr  "10/30/2015 09:00:00" "10/30/2015 09:01:00" "10/30/2015 09:02:00" "10/30/2015 09:03:00" ...
 $ V2: num  22443 22553 22578 22565 22574 ...

Меня интересует первая колонка, строковый формат такой:

df[1,1]
[1] "10/30/2015 09:00:00" # all the days are the same, the time are always different

Цель состоит в том, чтобы создать вектор или заменить df[,1] следующим:

[1] "0900" "0901" "0902" "0903" "0904" ... "1000" "1001" # character format

Или (предпочтительно) этим:

[1]  900  901  902  903  904 1000 1001 # numeric format

Используя самый быстрый способ.

Что у меня сейчас есть:

temp<-sapply(strsplit(df[,1],' '), "[", 2)
final<-paste0(substr(temp,1,2),substr(temp,4,5))

Который возвращает это:

final
[1] "0900" "0901" "0902"

Но это решение не очень эффективное. Я посмотрел на sub, которые позволяют мне это делать:

temp2<-sub(".*\\s","",df[,1])
[1] "09:00:00" "09:01:00" "09:02:00"

А затем я могу использовать paste0(substr(temp2,1,2),substr(temp2,4,5))

Но я хотел бы знать, можно ли создать шаблон , который позволяет мне использовать sub и возвращает непосредственно ожидаемый результат без необходимости использовать не очень красивый paste0(substr()) . Мне не удалось создать тот, который добавит часы и минуты и удалит все остальное. Я также пытался использовать strftime(as.POSIXct(df[,1],format="%m/%d/%Y %H:%M"), format="%H%M"), но это намного медленнее, чем мое первое решение.

Вот dput:

structure(list(V1 = c("10/30/2015 09:00:00", "10/30/2015 09:01:00", 
"10/30/2015 09:02:00", "10/30/2015 09:03:00", "10/30/2015 09:04:00", 
"10/30/2015 09:05:00", "10/30/2015 09:06:00", "10/30/2015 09:07:00", 
"10/30/2015 09:08:00", "10/30/2015 09:09:00", "10/30/2015 09:10:00", 
"10/30/2015 09:11:00", "10/30/2015 09:12:00", "10/30/2015 09:13:00", 
"10/30/2015 09:14:00", "10/30/2015 09:15:00", "10/30/2015 09:16:01", 
"10/30/2015 09:17:01", "10/30/2015 09:18:01", "10/30/2015 09:19:01", 
"10/30/2015 09:20:01", "10/30/2015 09:21:01", "10/30/2015 09:22:01", 
"10/30/2015 09:23:01", "10/30/2015 09:24:01", "10/30/2015 09:25:01", 
"10/30/2015 09:26:01", "10/30/2015 09:27:01", "10/30/2015 09:28:01", 
"10/30/2015 09:29:01", "10/30/2015 09:30:01", "10/30/2015 09:31:01", 
"10/30/2015 09:32:01", "10/30/2015 09:33:01", "10/30/2015 09:34:01", 
"10/30/2015 09:35:07", "10/30/2015 09:36:07", "10/30/2015 09:37:07", 
"10/30/2015 09:38:07", "10/30/2015 09:39:07", "10/30/2015 09:40:07", 
"10/30/2015 09:41:07", "10/30/2015 09:42:07", "10/30/2015 09:43:07", 
"10/30/2015 09:44:07", "10/30/2015 09:45:07", "10/30/2015 09:46:07", 
"10/30/2015 09:47:07", "10/30/2015 09:48:07", "10/30/2015 09:49:07", 
"10/30/2015 09:50:07", "10/30/2015 09:51:07", "10/30/2015 09:52:07", 
"10/30/2015 09:53:07", "10/30/2015 09:54:08", "10/30/2015 09:55:08", 
"10/30/2015 09:56:08", "10/30/2015 09:57:08", "10/30/2015 09:58:08", 
"10/30/2015 09:59:08", "10/30/2015 10:00:08", "10/30/2015 10:01:08", 
"10/30/2015 10:02:08", "10/30/2015 10:03:08", "10/30/2015 10:04:08", 
"10/30/2015 10:05:09", "10/30/2015 10:06:09", "10/30/2015 10:07:09", 
"10/30/2015 10:08:09", "10/30/2015 10:09:09", "10/30/2015 10:10:09", 
"10/30/2015 10:11:09", "10/30/2015 10:12:09", "10/30/2015 10:13:09", 
"10/30/2015 10:14:10"), V2 = c(22442.6858524496, 22552.7748887668, 
22577.9648686789, 22564.8417742602, 22573.7958926466, 22561.6260074242, 
22578.4969273076, 22573.9368593738, 22560.5696621363, 22583.6351125504, 
22563.9244299535, 22541.3550854309, 22535.1792445106, 22538.7283516493, 
22541.9685357942, 22549.673693988, 22536.0848222147, 22544.616494178, 
22545.9428853405, 22537.299523422, 22540.5364098182, 22528.1021034889, 
22511.3116720369, 22506.3479483641, 22507.558168335, 22527.1208239657, 
22538.2049982901, 22541.7992712468, 22549.7770949926, 22528.0226154986, 
22530.5431405792, 22549.9493136773, 22552.9504121553, 22563.3834376963, 
22569.1331816863, 22563.530786576, 22548.534182103, 22557.2196783034, 
22558.8349158659, 22558.4231669129, 22560.8480363532, 22549.1149362013, 
22538.496220018, 22540.2035600505, 22552.7047151487, 22545.3585981628, 
22551.2236255021, 22545.3629088232, 22539.8878805106, 22555.054048293, 
22548.3256620096, 22546.9335769395, 22539.6190972632, 22533.8926489234, 
22533.6247376657, 22536.8700903098, 22541.8482702231, 22537.8380668048, 
22546.8597666549, 22524.5161580447, 22518.2836071664, 22517.0611422674, 
22528.2131886847, 22530.156289448, 22516.2954996312, 22520.3056133929, 
22509.8912888173, 22491.7907956155, 22488.6023084655, 22476.1342466018, 
22477.0124169306, 22472.3565080568, 22475.1373622179, 22467.2661513395, 
22474.9329072207)), .Names = c("V1", "V2"), row.names = c(NA, 
-75L), class = "data.frame")
1
etienne 30 Окт 2015 в 12:42

2 ответа

Лучший ответ

Если вы уверены, что все введенные вами данные имеют известный формат, вы можете использовать

sub("^\\S+\\s+(\\d+):(\\d+).*$","\\1\\2", s)

Подшаблон \\S+ соответствует 1 или более символам без пробелов, а .* соответствует 0 или более символам, кроме новой строки (жадно, но здесь это не имеет значения, поскольку мы сопоставляем остальную часть строки до конец - я предполагаю, что на входе нет символов новой строки).

См. демонстрацию IDEONE

Если вам нужно обрабатывать только строки, соответствующие формату dd/MM/yyyy hh:mm:ss (помимо других форматов), используйте

sub("^\\d+(?:/\\d+){2}\\s+(\\d+):(\\d+):\\d+$","\\1\\2", s)

Пояснение:

  • ^ - начало строки
  • \\d+ - 1 или более цифр
  • (?:/\\d+){2} - 2 вхождения (из-за ограничивающего квантификатора {2}) косой черты, за которой следует 1 или более цифр
  • \\s+ - 1 или несколько пробелов
  • (\\d+) - (Группа 1, на которую мы обратимся с \\1) 1 или более цифр
  • : - буквальное двоеточие
  • (\\d+) - (Group 1 that we'll backreference to with \ 1`) 1 или более цифр
  • :\\d+ - двоеточие, за которым следует 1 или несколько цифр (но мы не фиксируем их, поскольку нам не нужно их хранить)
  • $ - конец строки

См. Эту демонстрацию IDEONE

По сути, метод состоит в том, чтобы сопоставить всю строку, захватить (с помощью групп захвата (...)), что нам нужно сохранить, и в шаблоне замены использовать обратные ссылки (например, {{X1} } где n - индекс группы захвата) для захваченных подстрок.

3
Wiktor Stribiżew 30 Окт 2015 в 10:01

Если формат фиксирован, мы можем использовать substr:

as.numeric(
  paste0(substr(df$V1, 12, 13),
         substr(df$V1, 15, 16)))

Бенчмаркинг:

library(microbenchmark)
microbenchmark(
  substr={
    as.numeric(
      paste0(substr(df$V1, 12, 13),
             substr(df$V1, 15, 16)))
  },
  sub={
    as.numeric(sub("^\\d+(?:/\\d+){2}\\s+(\\d+):(\\d+):\\d+$",
                   "\\1\\2",
                   df$V1))
  },
  strsplit={
    temp <- sapply(strsplit(df[,1],' '), "[", 2)
    as.numeric(paste0(substr(temp,1,2),substr(temp,4,5)))
  },
  times=1000)

Unit: microseconds
     expr     min      lq      mean  median      uq      max neval cld
   substr  46.786  50.711  61.08613  52.220  54.031 6657.496  1000 a  
      sub 127.078 132.813 139.43847 135.831 141.264  251.136  1000  b 
 strsplit 143.679 151.829 162.15411 157.866 166.016  331.426  1000   c
1
zx8754 30 Окт 2015 в 10:07