Заменить NA условиями - PullRequest
       15

Заменить NA условиями

0 голосов
/ 08 марта 2019

Я пытаюсь провести анализ, для которого мне нужно иметь все столбцы моих данных со значениями.

У меня есть список многих пациентов.Пациенты рассматриваются в 3 возможных ситуациях: неотложные состояния, амбулаторные консультации и госпитализация.

Каждый пациент может посещать эти службы один или несколько раз.

Имеются следующие данные:

  • Число
  • Дата
  • диагноз в отделении неотложной помощи
  • диагноз в амбулаторных консультациях
  • диагноз при госпитализации

Проблема заключается в том, что пациент приходит в отделение неотложной помощи, толькодиагноз экстренной помощи будет заполнен к этой дате, внешние консультации и госпитализация будут иметь «NA».Точно так же, как если бы вы приходили в амбулаторию, у вас будет АН в отделении неотложной помощи и госпитализации на эту дату (когда вы приходите в поликлинику).

 pacient <- c(10,10,10,10,10,11,11,12,12,12); pacient
date <- as.Date(c("01/01/2018","02/01/2018", "04/04/2018", "10/05/2018", "05/09/2018", "02/01/2018", "06/08/2018", "01/01/2018", "03/01/2018", "06/08/2018"), format = "%d/%m/%Y"); date 
set <- c("URG", "CEX", "CEX", "URG", "HOSP", "CEX", "URG", "CEX", "CEX", "URG")
dx_URG <- c("A", NA, NA, "B", NA, NA, "A", NA, NA, "B")
dx_CEX <- c(NA, "B", "C", NA, NA, "A", NA, "C", "B", NA)
dx_HOSP <- c(NA, NA, NA, NA, "A", NA, NA, NA,NA,NA)

DF <- data.frame(pacient, date, set, dx_URG, dx_CEX, dx_HOSP)); DF

Мои данные:

        pacient    date      set   dx_URG dx_CEX dx_HOSP
1       10     01/01/2018    URG      A   <NA>   <NA>
2       10     02/01/2018    CEX   <NA>      B   <NA>
3       10     04/04/2018    CEX   <NA>      C   <NA>
4       10     10/05/2018    URG      B   <NA>   <NA>
5       10     05/09/2018    HOSP   <NA>   <NA>    A
6       11     02/01/2018    CEX   <NA>      A   <NA>
7       11     06/08/2018    URG      A   <NA>   <NA>
8       12     01/01/2018    CEX   <NA>      C   <NA>
9       12     03/01/2018    CEX   <NA>      B   <NA>
10      12     06/08/2018    URG      B   <NA>   <NA>
  • Заполните NA столбца, если это возможно, собственными значениями пациента.То есть пациент 10 приходил в больницу 5 раз в 5 разных дат.При первом посещении генерируется NA в CEX и HOSP, посещение 2 в URG и HOSP ... и так далее.Я хочу заполнить пропущенные значения для пациента 10 в столбце dx_URG самым последним экстренным диагнозом для этого пациента, то есть вы:

A, B, B, B,B

Первое значение остается прежним, второе - NA становится B (так как датировано 10/05/2018 визитом в URG, который ставит диагноз B) и так ... Это для диагностики в CEXпациента 10, я заполнил NA с диагнозом C и для диагностики в HOSP с диагнозом A. Это я достиг, частично, с помощью следующего кода:

dx_remp <- lapply(DF, function(x){
  setDT(DF)[, dx_URG:= na.aggregate(dx_URG, FUN=function(x){ tail(x[!is.na(x)],1)}), by = pacient]
  setDT(DF)[, dx_CEX:= na.aggregate(dx_CEX, FUN=function(x){ tail(x[!is.na(x)],1)}), by = pacient]
  setDT(DF)[, dx_HOSP:= na.aggregate(dx_HOSP, FUN=function(x){ tail(x[!is.na(x)],1)}), by = pacient]
  return(num_vist)})

Проблема в том, что этот кодне работает, если у пациента нет диагноза «заполнить»: например, я получаю ошибку при заполнении dx_HOSP, поскольку ни у пациента 11, ни у 12 нет никакого значения.

Второе, что мне нужноВ связи с этим, если у пациентов нет значений для заполнения в столбце, в котором мы заменяем NA, искать его в другом из столбцов: приоритет будет CEX -> HOSP -> URG

Таким образом, я должен сначала заполнить NA, заглянув внутрь столбца, если не было значений, выполнить поиск в dx_CEX, затем в dx_HOS, затем в dx_URG.

Требуемый результат:

       pacient    date      set   dx_URG dx_CEX dx_HOSP
1       10     01/01/2018    URG      A      C     A
2       10     02/01/2018    CEX      B      B     A
3       10     04/04/2018    CEX      B      C     A
4       10     10/05/2018    URG      B      C     A
5       10     05/09/2018    HOSP     B      C     A
6       11     02/01/2018    CEX      A      A     A
7       11     06/08/2018    URG      A      A     A
8       12     01/01/2018    CEX      B      C     B
9       12     03/01/2018    CEX      B      B     B
10      12     06/08/2018    URG      B      B     B

Например, пациент 10 в dx_cex имеет пустые даты 1, 4 и 5;NA dx_cex должен быть заполнен последним диагнозом cex для этого пациента, то есть C. У пациента 12 в dx_hosp он не имеет значения ни в одном из цитирований, поэтому необходимо искать последний действительный диагноз вcex, то есть B и заполнить все NA dx_hosp с помощью B.

Спасибо

Ответы [ 2 ]

1 голос
/ 08 марта 2019

Адаптация на основе новых данных. Мы создаем вспомогательную функцию, которая заполняет значения NA последним не NA значением (если оно есть), и используем его вместо fill:

fill_with_last = function(x)  {
  if (any(!is.na(x))) x[is.na(x)] = tail(na.omit(x), 1)
  return(x)
}

DF %>% 
  # fix column classes (just in case)
  mutate_if(is.factor, as.character) %>%
  # ensure order is correct
  arrange(pacient, date) %>%
  # by pacient
  group_by(pacient) %>%
  # fill in the diagnosis variables with last observation
  mutate_at(vars(starts_with("dx")), fill_with_last) %>%
  # coalesce in priority order to fill in any blanks
  mutate(dx_URG = coalesce(dx_URG, dx_CEX, dx_HOSP),
         dx_CEX = coalesce(dx_CEX, dx_HOSP, dx_URG),
         dx_HOSP = coalesce(dx_HOSP, dx_CEX, dx_URG))

# # A tibble: 10 x 6
# # Groups:   pacient [3]
#    pacient date       set   dx_URG dx_CEX dx_HOSP
#      <dbl> <date>     <chr> <chr>  <chr>  <chr>  
#  1      10 2018-01-01 URG   A      C      A      
#  2      10 2018-01-02 CEX   B      B      A      
#  3      10 2018-04-04 CEX   B      C      A      
#  4      10 2018-05-10 URG   B      C      A      
#  5      10 2018-09-05 HOSP  B      C      A      
#  6      11 2018-01-02 CEX   A      A      A      
#  7      11 2018-08-06 URG   A      A      A      
#  8      12 2018-01-01 CEX   B      C      C      
#  9      12 2018-01-03 CEX   B      B      B      
# 10      12 2018-08-06 URG   B      B      B      

Обратите внимание, что в строке dx_Hosp есть расхождение. Ваш желаемый результат показывает "B", но описанная вами логика (реализованная и мной, и Синдри) приводит к "C", потому что dx_CEX предшествует dx_URG в порядке приоритета.


Вот оригинальное решение, когда я думал, что вы хотите поставить диагноз следующий , а не диагноз последний . Он использует tidyr для своей функции fill (заполняет пропущенные значения предыдущим наблюдением) и dplyr для своей функции coalesce (принимает первое непропущенное значение по столбцам):

library(tidyr)
library(dplyr)

DF %>%
  # convert any factor columns to character for easy modification
  mutate_if(is.factor, as.character) %>%
  # make sure things are in the right order
  arrange(pacient, date) %>%
  # do subsequent operations "by pacient"
  group_by(pacient) %>% 
  # fill in missing values "up" with the most recent observation,
  # then fill "down" if there are other holes
  fill(dx_URG, dx_CEX, dx_HOSP, .direction = "up") %>%
  fill(dx_URG, dx_CEX, dx_HOSP, .direction = "down") %>%
  # "coalesce" column in the order of preference
  mutate(dx_URG = coalesce(dx_URG, dx_CEX, dx_HOSP),
         dx_CEX = coalesce(dx_CEX, dx_HOSP, dx_URG),
         dx_HOSP = coalesce(dx_HOSP, dx_CEX, dx_URG))
# # A tibble: 10 x 6
# # Groups:   pacient [3]
#    pacient date       set   dx_URG dx_CEX dx_HOSP
#      <dbl> <date>     <chr> <chr>  <chr>  <chr>  
#  1      10 2018-01-01 URG   A      B      A      
#  2      10 2018-01-02 CEX   B      B      A      
#  3      10 2018-04-04 CEX   B      C      A      
#  4      10 2018-05-10 URG   B      C      A      
#  5      10 2018-09-05 HOSP  B      C      A      
#  6      11 2018-01-02 CEX   A      A      A      
#  7      11 2018-08-06 URG   A      A      A      
#  8      12 2008-01-01 CEX   B      C      C      
#  9      12 2018-01-03 CEX   B      B      B      
# 10      12 2018-08-06 URG   B      B      B      

Пара примечаний к данным. В вашем коде у вас был год 2008 в строке 5, но в вашей таблице у вас был 2018, как и у всех остальных. Я изменил 2008 на 2018, чтобы соответствовать таблице.

Когда вы делаете cbind(), он конвертирует все в matrix, что приводит к потере классов столбцов. Это плохо. Гораздо лучше позвонить data.frame() напрямую, чем использовать as.data.frame(cbind()).

# change this
DF <- as.data.frame(cbind(pacient, date, set, dx_URG, dx_CEX, dx_HOSP))
# to this
DF <- data.frame(pacient, date, set, dx_URG, dx_CEX, dx_HOSP)
0 голосов
/ 12 марта 2019

Я подумал, что это забавная проблема, и придумал решение data.table, которое для удобства чтения dplyr::case_when():

# Setup ----
# Packages
library(dplyr)
library(data.table)

# Convert to data.table
setDT(DF)
# Get the order of in terms of pacient and date
setkey(DF, pacient, date)
# Convert factors to characters (easier to work with)
factors <- names(DF)[sapply(DF, is.factor)]
DF[,(factors):= lapply(.SD, as.character), .SDcols = factors]
# Define helper function
ext_most_recent <- function(x) tail(x[!is.na(x)], 1) 
# Which columns to update
cols2fill <- c("dx_URG", "dx_CEX", "dx_HOSP")

# Update columns ----
DF[, (cols2fill) := lapply(
                      .SD, 
                      function(x) {
                        most_recent <- ext_most_recent(x)[1]
                        case_when(
                          !is.na(x) ~ x,
                          !is.na(most_recent) ~ most_recent,
                          !is.na(dx_CEX) ~ dx_CEX,
                          !is.na(dx_HOSP) ~ dx_HOSP,
                          !is.na(dx_URG) ~ dx_URG,
                          TRUE ~ NA_character_
                        )
                      }
                    ), 
   by = pacient, 
   .SDcols = c("dx_URG", "dx_CEX", "dx_HOSP")]

#  1:      10 2018-01-01  URG      A      C       A
#  2:      10 2018-01-02  CEX      B      B       A
#  3:      10 2018-04-04  CEX      B      C       A
#  4:      10 2018-05-10  URG      B      C       A
#  5:      10 2018-09-05 HOSP      B      C       A
#  6:      11 2018-01-02  CEX      A      A       A
#  7:      11 2018-08-06  URG      A      A       A
#  8:      12 2018-01-01  CEX      B      C       C
#  9:      12 2018-01-03  CEX      B      B       B
# 10:      12 2018-08-06  URG      B      B       B
...