Векторизация условных строк - PullRequest
1 голос
/ 12 февраля 2020

Я пытаюсь сделать следующее векторизованное манипулирование столбцом даты в моих данных. Я нашел очень не элегантное решение и уверен, что есть более чистое и аккуратное решение. Пример игрушки:

index <- c(1,2)
input <- c('11-9-2019', '11/01/2019-01/31/2020')
output <- c('11-9-2019', '11-01-2019')

df_in <- data.frame('index'=index, 'data'=input)

df_out <- data.frame('index' =index, 'data'=output)

Я могу решить проблему с помощью sapply следующим образом:

df_out$data <- sapply(range(1:2), function(x) ifelse(str_length(df_in$data[x]) > 12, 
                                          str_sub(df_in$data[x], -10, -1), 
                                                  df_in$data[x]))
df_out$data <- str_replace_all(df_out$data, '/', '-')
df_out$data

Есть ли способ сделать это а) с одной векторизованной линией, б), не полагаясь на строковые индексы, как я делал в str_sub?

Спасибо!

Ответы [ 3 ]

3 голосов
/ 12 февраля 2020

Вы можете сделать это, используя gsub:

 gsub("(\\d{1,2})[/-](\\d{1,2})[/-](\\d{4}).*","\\1-\\2-\\3",df_in$data)
 [1] "11-9-2019"  "11-01-2019"

Объяснение, если вы не знакомы с регулярным выражением:

Поиск строки, состоящей из одной или двух цифр ((\\d{1,2})), затем следуют sla sh или da sh ([/-]), затем еще одна или две цифры, снова da sh или sla sh, а затем четыре цифры. Он заменяет их только тремя наборами цифр, разделенными черточками, и удаляет все, что следует за этой первой строкой.

1 голос
/ 12 февраля 2020

Другой вариант в tidyverse - разделить элементы с separate_rows, а затем преобразовать в Date класс с lubridate

library(lubridate)
library(dplyr)
library(tidyr)
df_in %>% 
   separate_rows(data, sep="-(?=[0-9]{2}[^0-9])") %>%
   group_by(index) %>%
   slice(1) %>% 
   transmute(data = lubridate::mdy(data)) %>%
   pull(data)
#[1] "2019-11-09" "2019-11-01"
0 голосов
/ 12 февраля 2020

Идея состоит в том, чтобы использовать mdy (день месяца год) из lubridate после удаления любых лишних дат, т. Е.

lubridate::mdy(ifelse(nchar(df_in$data > 10), substr(df_in$data, 1, 10), df_in$data))
#[1] "2019-11-09" "2019-11-01"
...