r: почему символьная строка показывает дни, а не дату при применении as.Date() и origin?

#r #dataframe #date #lubridate

#r #dataframe #Дата #lubridate

Вопрос:

У меня есть

 > head(p, 10)
   date_contact mr_daterd_fu1
1                  11.10.2012
2                            
3                            
4                            
5    13.12.1994              
6                            
7    20.03.2012    20.03.2012
8    25.08.1999              
9    25.05.2012    25.05.2012
10   19.10.2007 
 

Мне нужно заменить отсутствующие значения в p$date_contact на p$mr_daterd_fu1 as в

 fu1_date = ifelse(is.na(date_contact), 
                  as.Date(mr_daterd_fu1,  format = '%d.%m.%Y'),
                  as.Date(date_contact,  format = '%d.%m.%Y')))
 

Но это дает

 > head(p, 10)
   date_contact mr_daterd_fu1 fu1_date
1                  11.10.2012       NA
2                                   NA
3                                   NA
4                                   NA
5    13.12.1994                   9112
6                                   NA
7    20.03.2012    20.03.2012    15419
8    25.08.1999                  10828
9    25.05.2012    25.05.2012    15485
10   19.10.2007                  13805
 

И

 > str(p)
'data.frame':   946 obs. of  3 variables:
 $ date_contact : chr  "" "" "" "" ...
 $ mr_daterd_fu1: chr  "11.10.2012" "" "" "" ...
 $ fu1_date     : num  NA NA NA NA 9112 ...
 

Почему p$fu1_date не отображается as.Date ?

Я пытался

  p %>% mutate(mr_daterd_fu1 = as.Date(mr_daterd_fu1,  format = '%d.%m.%Y'),
         fu1_date = ifelse(is.na(date_contact), 
                    mr_daterd_fu1,
                    as.Date(date_contact,  format = '%d.%m.%Y', origin=mr_daterd_fu1)))
 

Но это не сработало.

Ожидаемый результат:

    date_contact mr_daterd_fu1    fu1_date
1                  11.10.2012  2012.10.11
2                                      NA
3                                      NA
4                                      NA
5    13.12.1994                1994.12.13
6                                      NA
7    20.03.2012    20.03.2012  2012.03.20
8    25.08.1999                1999.08.25
9    25.05.2012    25.05.2012  2012.05.25
10   19.10.2007                2007.10.19
 

Данные

 p <- structure(list(date_contact = c("", "", "", "", "13.12.1994", 
"", "20.03.2012", "25.08.1999", "25.05.2012", "19.10.2007"), 
    mr_daterd_fu1 = c("11.10.2012", "", "", "", "", "", "20.03.2012", 
    "", "25.05.2012", "")), row.names = c(NA, 10L), class = "data.frame")
 

Ответ №1:

Мы можем преобразовать в Date класс и использовать coalesce

 library(dplyr)
p %>%
   mutate(across(c(date_contact, mr_daterd_fu1),
           as.Date, format = "%d.%m.%Y")) %>% 
   mutate(ful_date  = coalesce(date_contact, mr_daterd_fu1 ))
 

-вывод

 #  date_contact mr_daterd_fu1   ful_date
#1          <NA>    2012-10-11 2012-10-11
#2          <NA>          <NA>       <NA>
#3          <NA>          <NA>       <NA>
#4          <NA>          <NA>       <NA>
#5    1994-12-13          <NA> 1994-12-13
#6          <NA>          <NA>       <NA>
#7    2012-03-20    2012-03-20 2012-03-20
#8    1999-08-25          <NA> 1999-08-25
#9    2012-05-25    2012-05-25 2012-05-25
#10   2007-10-19          <NA> 2007-10-19
 

В общем, лучше не использовать ifelse с Date class

Комментарии:

1. Привет, акрун. Спасибо за ваш вклад. В моем наборе данных есть множество ковариаций, поэтому across(everything().. их не следует преобразовывать as.Date , только ковариации, упомянутые в вопросе.

2. Привет @akrun — дополнительный вопрос; возможно ли применить ваш метод как-то к эффекту: mutate(across(c("all columns that contain "date_contact", all columns that contain "mr_daterd"), as.Date, format = "%d.%m.%Y")) ?

3. Вы можете использовать matches("date_contact|mr_daterd")

4. Спасибо за быстрый ответ. Получено сообщение об ошибке mutate(across(matches(date_contact | mr_daterd), as.Date, format = "%d.%m.%Y")) . Я думаю, это потому, что столбцы содержат date_contact и mr_daterd как часть большего имени столбца, например. mr_daterd_fu1 . Поэтому он должен выглядеть примерно так all columns that contain date_contact|mr_daterd — можно ли это сделать?

5. @cmirian большинство помощников по выбору принимают строку, т.е. contains matches

Ответ №2:

Вы также можете попробовать это. В ваших данных есть пустые места, поэтому is.na() они не работают:

 library(dplyr)
#Code
p %>% mutate(mr_daterd_fu1 = as.Date(mr_daterd_fu1,  format = '%d.%m.%Y'),
             fu1_date = if_else(date_contact=='', 
                               mr_daterd_fu1,
                               as.Date(date_contact,  format = '%d.%m.%Y', origin=mr_daterd_fu1)))
 

Вывод:

    date_contact mr_daterd_fu1   fu1_date
1                  2012-10-11 2012-10-11
2                        <NA>       <NA>
3                        <NA>       <NA>
4                        <NA>       <NA>
5    13.12.1994          <NA> 1994-12-13
6                        <NA>       <NA>
7    20.03.2012    2012-03-20 2012-03-20
8    25.08.1999          <NA> 1999-08-25
9    25.05.2012    2012-05-25 2012-05-25
10   19.10.2007          <NA> 2007-10-19