Как пропустить NA при расчете разницы во времени в R - PullRequest
1 голос
/ 16 апреля 2020

У меня есть фрейм данных со столбцом идентификатора, столбцом даты и столбцом с указанными c датами обработки идентификатора. Идентификатор не обрабатывается в каждую отдельную дату, поэтому в столбце даты обработки есть NA, если идентификатор не обрабатывался. Я хочу создать новый столбец с количеством дней, прошедших с предыдущей даты лечения.

#sample data
df1 <- data.frame(ID = c("82002","82002","82002","82002","82002","82002","82002",
                         "82002","82002","82002","82002","82002"),
                  MtDate = c("2019-07-17","2019-07-17","2019-07-18","2019-07-18","2019-07-18",
                             "2019-07-19","2019-07-19","2019-07-19","2019-07-21",
                             "2019-07-21","2019-07-22","2019-07-23"),
                  TrtDate = c("2019-07-17","NA","2019-07-21", "NA", "NA",
                              "NA", "NA", "NA", "NA","NA", "NA", "2019-07-23"))
#format MtDate and TrtDate columns as dates
df1$MtDate = ymd(df1$MtDate)
df1$TrtDate = ymd(df1$TrtDate)

Я пытался использовать mutate и вычитать текущую дату лечения из предыдущей даты лечения, которая работает для строк, где TrtDate не NA

df1 <- df1 %>%
arrange(TrtDate) %>%
mutate(DaysSincePrevTreat = TrtDate - lag(TrtDate, default = first(TrtDate)))%>%
data.frame()

Дая мне этот результат

> df1
       MtDate    TrtDate DaysSincePrevTreat
1  2019-07-17 2019-07-17             0 days
2  2019-07-18 2019-07-21             4 days
3  2019-07-23 2019-07-23             2 days
4  2019-07-17       <NA>            NA days
5  2019-07-18       <NA>            NA days
6  2019-07-18       <NA>            NA days
7  2019-07-19       <NA>            NA days
8  2019-07-19       <NA>            NA days
9  2019-07-19       <NA>            NA days
10 2019-07-21       <NA>            NA days
11 2019-07-21       <NA>            NA days
12 2019-07-22       <NA>            NA days

Но то, что я не хочу «игнорировать» даты, когда TrtDate = NA, и количество дней с предыдущей даты обработки в столбце DaysSincePrevTreat для каждого MtDate .... Ниже мой желаемый результат

> Desired.Result
      ID     MtDate    TrtDate DaysSincePrevTreat
1  82002 2019-07-17 2019-07-17                  0
2  82002 2019-07-17 2019-07-17                  0
3  82002 2019-07-18         NA                  1
4  82002 2019-07-18         NA                  1
5  82002 2019-07-18         NA                  1
6  82002 2019-07-19         NA                  2
7  82002 2019-07-19         NA                  2
8  82002 2019-07-19         NA                  2
9  82002 2019-07-21 2019-07-21                  0
10 82002 2019-07-21 2019-07-21                  0
11 82002 2019-07-22         NA                  1
12 82002 2019-07-23 2019-07-23                  0

Я мог бы сделать это вручную, но мои фактические данные включают в себя более 100 000 баллов и более 200 различных дат лечения. Будем очень благодарны любой помощи. Спасибо!

1 Ответ

0 голосов
/ 16 апреля 2020

Я бы использовал tidyr::fill (задокументировано здесь ), чтобы заполнить значения NA TrtDate вперед в вашем data.frame. Это позволит вам эффективно «пропустить» значения NA при расчете интересующих вас количеств в вашем data.frame. Я хотел бы выполнить этот тип действия с копией исходного поля данных, чтобы вы могли визуально проверить логи c и восстановить значения NA, если это необходимо.

Некоторый код для этого (плюс некоторая часть вашей очистки / нормализации данных):

df1 %>% 
     # convert to dates
     dplyr::mutate(TrtDate = lubridate::ymd(dplyr::na_if(TrtDate, "NA")),
                   MtDate = lubridate::ymd(dplyr::na_if(MtDate, "NA"))) %>%
     dplyr::group_by(ID) %>% 
     # sort by MtDate
     dplyr::arrange(MtDate) %>%
     # create a copy of TrtDate which we will use for filling
     dplyr::mutate(FillTrtDate = TrtDate) %>% 
     # fill forward 
     tidyr::fill(FillTrtDate, .direction = 'down') %>% 
     # compute difference
     dplyr::mutate(PrevTrtDate = lag(FillTrtDate, default = first(TrtDate), order_by = MtDate),
         DaysSincePrevTreat = MtDate - PrevTrtDate) %>%  
     dplyr::ungroup()

Результат:

# A tibble: 12 x 6
   ID    MtDate     TrtDate    FillTrtDate PrevTrtDate DaysSincePrevTreat
   <fct> <date>     <date>     <date>      <date>      <drtn>            
 1 82002 2019-07-17 2019-07-17 2019-07-17  2019-07-17   0 days           
 2 82002 2019-07-17 NA         2019-07-17  2019-07-17   0 days           
 3 82002 2019-07-18 2019-07-21 2019-07-21  2019-07-17   1 days           
 4 82002 2019-07-18 NA         2019-07-21  2019-07-21  -3 days           
 5 82002 2019-07-18 NA         2019-07-21  2019-07-21  -3 days           
 6 82002 2019-07-19 NA         2019-07-21  2019-07-21  -2 days           
 7 82002 2019-07-19 NA         2019-07-21  2019-07-21  -2 days           
 8 82002 2019-07-19 NA         2019-07-21  2019-07-21  -2 days           
 9 82002 2019-07-21 NA         2019-07-21  2019-07-21   0 days           
10 82002 2019-07-21 NA         2019-07-21  2019-07-21   0 days           
11 82002 2019-07-22 NA         2019-07-21  2019-07-21   1 days           
12 82002 2019-07-23 2019-07-23 2019-07-23  2019-07-21   2 days     

Что эта структура проясняет, так это то, что Есть некоторые несоответствия в ваших исходных данных примера и желаемого результата. Но это те проблемы, которые приведенные выше инструменты должны помочь вам решить.

edit: подробности о "несоответствиях"

Предоставленный фрейм данных был:

> df1
      ID     MtDate    TrtDate
1  82002 2019-07-17 2019-07-17
2  82002 2019-07-17         NA
3  82002 2019-07-18 2019-07-21
4  82002 2019-07-18         NA
5  82002 2019-07-18         NA
6  82002 2019-07-19         NA
7  82002 2019-07-19         NA
8  82002 2019-07-19         NA
9  82002 2019-07-21         NA
10 82002 2019-07-21         NA
11 82002 2019-07-22         NA
12 82002 2019-07-23 2019-07-23

По вашему желаемому выводу, опечатка есть на 3-й запись. Исправляя это, получим:

df2 <- data.frame(ID = c("82002","82002","82002","82002","82002","82002","82002",
                         "82002","82002","82002","82002","82002"),
                  MtDate = c("2019-07-17","2019-07-17","2019-07-18","2019-07-18","2019-07-18",
                             "2019-07-19","2019-07-19","2019-07-19","2019-07-21",
                             "2019-07-21","2019-07-22","2019-07-23"),
                  TrtDate = c("2019-07-17","NA","2019-07-18", "NA", "NA",
                              "NA", "NA", "NA", "NA","NA", "NA", "2019-07-23"))

или

> df2
      ID     MtDate    TrtDate
1  82002 2019-07-17 2019-07-17
2  82002 2019-07-17         NA
3  82002 2019-07-18 2019-07-18
4  82002 2019-07-18         NA
5  82002 2019-07-18         NA
6  82002 2019-07-19         NA
7  82002 2019-07-19         NA
8  82002 2019-07-19         NA
9  82002 2019-07-21         NA
10 82002 2019-07-21         NA
11 82002 2019-07-22         NA
12 82002 2019-07-23 2019-07-23

Чтобы получить желаемый результат, я бы заполнил вперед, как указано выше, но пропустил шаг lag:

df2 %>% 
    # convert to dates
    dplyr::mutate(TrtDate = lubridate::ymd(dplyr::na_if(TrtDate, "NA")),
                  MtDate = lubridate::ymd(dplyr::na_if(MtDate, "NA"))) %>%
    dplyr::group_by(ID) %>% 
    # sort by MtDate
    dplyr::arrange(MtDate) %>%
    # create a copy of TrtDate which we will use for filling
    dplyr::mutate(FillTrtDate = TrtDate) %>% 
    # fill forward 
    tidyr::fill(FillTrtDate, .direction = 'down') %>% 
    # compute difference, while converting to dates
    dplyr::mutate(DaysSincePrevTreat = MtDate - FillTrtDate) %>%  
    dplyr::ungroup()

или

# A tibble: 12 x 5
   ID    MtDate     TrtDate    FillTrtDate DaysSincePrevTreat
   <fct> <date>     <date>     <date>      <drtn>            
 1 82002 2019-07-17 2019-07-17 2019-07-17  0 days            
 2 82002 2019-07-17 NA         2019-07-17  0 days            
 3 82002 2019-07-18 2019-07-18 2019-07-18  0 days            
 4 82002 2019-07-18 NA         2019-07-18  0 days            
 5 82002 2019-07-18 NA         2019-07-18  0 days            
 6 82002 2019-07-19 NA         2019-07-18  1 days            
 7 82002 2019-07-19 NA         2019-07-18  1 days            
 8 82002 2019-07-19 NA         2019-07-18  1 days            
 9 82002 2019-07-21 NA         2019-07-18  3 days            
10 82002 2019-07-21 NA         2019-07-18  3 days            
11 82002 2019-07-22 NA         2019-07-18  4 days            
12 82002 2019-07-23 2019-07-23 2019-07-23  0 days      

Затем вы можете select(-FillTrtDate) удалить этот вспомогательный столбец, если хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...