Как заменить значения в нескольких условиях с помощью purrr?

Сообщение было отредактировано 17 августа 2020 г., чтобы пример больше походил на мои настоящие данные.

Дни всегда начинаются с 1 или 2 цифр. Месяцы всегда идут вторыми полностью или частично и по-французски. Годы всегда идут на третьем месте с 2-мя или 4-мя цифрами.


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

Вот воспроизводимый пример:

library(tidyverse)
library(magrittr)
        
tib <- tibble(
  ID = 1:6, 
  Date = c("1-JAN-20", "15-JUILL-20", "30 DEC 2020", 
           "1-JAN-20", "15-JUILL-20", "30 DEC 2020"), 
  Comm = c("Should be 2020-01-01", "Should be 2020-06-15", "Should be 2020-12-30", 
           "Should be 2020-01-01", "Should be 2020-06-15", "Should be 2020-12-30"))
head(tib)

# A tibble: 6 x 3
     ID Date        Comm                
  <int> <chr>       <chr>               
1     1 1-JAN-20    Should be 2020-01-01
2     2 15-JUILL-20 Should be 2020-06-15
3     3 30 DEC 2020 Should be 2020-12-30
4     4 1-JAN-20    Should be 2020-01-01
5     5 15-JUILL-20 Should be 2020-06-15
6     6 30 DEC 2020 Should be 2020-12-30

# Returns the unique values of the character variables execept the "Comm" one. So, it
# returns only one in that case, but my original data have severals ones.
            
tib %>% select(where(is.character), -Comm) %>% map(~ unique(.x))
    
$Date
[1] "1-JAN-20"   "15-JUILL-20" "30 DEC 2020"

Мы здесь! Следующий код работает, но мне интересно, есть ли лучший способ получить его вместо того, чтобы каждый раз копировать / передавать одну и ту же строку кода и изменять ее.

tib <- tib %>% mutate(Date = case_when(Date == "1-JAN-20" ~ "2020-01-01", 
                                       Date == "15-JUILL-20" ~ "2020-06-15",
                                       Date == "30 DEC 2020" ~ "2020-12-01"))
head(tib)

# A tibble: 6 x 3
     ID Date       Comm                
  <int> <chr>      <chr>               
1     1 2020-01-01 Should be 2020-01-01
2     2 2020-06-15 Should be 2020-06-15
3     3 2020-12-01 Should be 2020-12-30
4     4 2020-01-01 Should be 2020-01-01
5     5 2020-06-15 Should be 2020-06-15
6     6 2020-12-01 Should be 2020-12-30

Поскольку мне придется проделать эту манипуляцию с другими переменными, как я могу создать функцию, которая выполнит это?

Кроме того, я хотел бы знать, знаете ли вы какую-нибудь хорошую документацию / учебные пособия по изучению пакета Purrr?

Спасибо и хорошего дня!


person Mathieu Bernier    schedule 16.08.2020    source источник
comment
одна из самых важных вещей - не вставлять rm(list=ls()) при размещении здесь своего кода, потому что пользователь, воспроизводящий ваш код, может случайно удалить свои переменные.   -  person daniellga    schedule 16.08.2020


Ответы (2)


При обработке даты / времени вы должны использовать стандартные функции даты и времени для манипуляций. Не заменяйте даты одну за другой, используя str_replace. Представьте, что у вас есть тысячи дат с разными годами, практически невозможно перечислить каждую из них. В этом случае вы можете использовать lubridate::dmy для преобразования их в объект даты, для более сложных случаев есть lubridate::parse_date_time, который может преобразовывать переменные в другом формате в даты.

tib %>% dplyr::mutate(new_date = lubridate::dmy(Date))

#     ID Date        Comm                 new_date  
#  <int> <chr>       <chr>                <date>    
#1     1 01-JAN-20   Should be 2020-01-01 2020-01-01
#2     2 15-JUN-20   Should be 2020-06-15 2020-06-15
#3     3 30 DEC 2020 Should be 2020-12-30 2020-12-30
#4     4 01-JAN-20   Should be 2020-01-01 2020-01-01
#5     5 15-JUN-20   Should be 2020-06-15 2020-06-15
#6     6 30 DEC 2020 Should be 2020-12-30 2020-12-30

Если вам нужны даты в определенном формате, вы можете использовать функцию format на new_date.

person Ronak Shah    schedule 17.08.2020
comment
Есть ли способ добиться этого, если ваш формат даты не является постоянным и стандартным. Я отредактировал сообщение, чтобы адаптировать пример и сделать его более похожим на мои настоящие данные. - person Mathieu Bernier; 17.08.2020
comment
Это странно, как Lubridate может знать, что 01-JAN-20 - это 2020-01-01, а не 1920-01-01? - person daniellga; 17.08.2020
comment
@MathieuBernier У вас должны быть свидания на одном языке, английском или французском. Кроме того, ваша локаль R должна быть на том же языке при использовании приведенного выше кода. Существует константа month.abb, которая дает вам название месяца в текущей локали. - person Ronak Shah; 17.08.2020
comment
@daniellga Это стандартный формат R, не относящийся к lubridate. От ?strptime - %y - On input, values 00 to 68 are prefixed by 20 and 69 to 99 by 19 - person Ronak Shah; 17.08.2020

Может быть, вы могли бы попробовать dplyr :: case_when:

library(magrittr)
library(purrr)

# A tibble that looks like my data.
tib <- tibble(
  ID = 1:6, 
  Date = c("01-JAN-20", "15-JUN-20", "30 DEC 2020", 
           "01-JAN-20", "15-JUN-20", "30 DEC 2020"), 
  Comm = c("Should be 2020-01-01", "Should be 2020-06-15", "Should be 2020-12-30", 
           "Should be 2020-01-01", "Should be 2020-06-15", "Should be 2020-12-30"))
head(tib)

tib %>% select(where(is.character), -Comm) %>% map(~ unique(.x))

tib <- tib %>% mutate(Date = dplyr::case_when(Date == "01-JAN-20" ~ "2020-01-01",
                                              Date == "15-JUN-20" ~ "2020-06-15",
                                              Date == "30 DEC 2020" ~ "2020-12-01"))

> tib
# A tibble: 6 x 3
     ID Date       Comm                
  <int> <chr>      <chr>               
1     1 2020-01-01 Should be 2020-01-01
2     2 2020-06-15 Should be 2020-06-15
3     3 2020-12-01 Should be 2020-12-30
4     4 2020-01-01 Should be 2020-01-01
5     5 2020-06-15 Should be 2020-06-15
6     6 2020-12-01 Should be 2020-12-30

Лучшее, что можно здесь сделать, - это преобразовать столбец Date в класс Date с помощью пакета anytime. Хотя вам придется вручную исправить столбец «Дата», чтобы все годы состояли из 4 цифр. Если годы всегда идут на последнем месте даты, это может быть легко сделать.

person daniellga    schedule 16.08.2020
comment
Я отредактировал пост, чтобы он больше походил на мои настоящие данные. Дни всегда начинаются с 1 или 2 цифр. Месяцы всегда идут посередине, но полностью или частично пишутся на французском языке. Годы всегда в конце, но иногда с 2 цифрами, а иногда с 4 цифрами. Придется ли мне менять их вручную? - person Mathieu Bernier; 17.08.2020
comment
@MathieuBernier, вы можете попробовать stri_replace_all или даже case_when, чтобы попытаться гомогенизировать месяцы на основе шаблонов, но остальные данные (день и год), я думаю, решение от Ronak позаботится об этом. - person daniellga; 17.08.2020