用条件替换不适用

时间:2019-03-08 11:56:20

标签: r replace na

我正在尝试进行分析,为此我需要使数据的所有列都具有值。

我有很多病人的清单。在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次。首次访问时,它会在CEX和HOSP中生成NA,在URG和HOSP中会访问2 ...等等。 我要在dx_URG列中填写患者10的缺失值,并为其提供最新的紧急诊断信息,也就是说您是:

A,B,B,B,B

第一个值保持不变,第二个是NA变为B(自2018年10月5日以来访问URG给出诊断B),因此... 为了在10位患者的CEX中进行诊断,我在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)})

问题是当患者没有诊断要“填写”时此代码不起作用:例如,由于患者11和12都没有任何值,我在填写dx_HOSP时出错。 >

与此有关的第二件事是,如果患者没有值来填充我们要替换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

例如,dx_cex中的患者10的日期为1、4和5为空; dx_cex的NA必须填写该患者的最后一次Cex诊断,即C。在dx_hosp的患者12中,在任何引用中均无价值,因此有必要在cex,即B,并用B填充dx_hosp的所有NA。

谢谢

2 个答案:

答案 0 :(得分:1)

基于新数据的适应。我们创建一个辅助函数,用最后一个非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第8行存在差异。您期望的结果显示为“ B”,但是您描述的逻辑(由我和sindri共同实现)的结果为“ C”,因为dx_CEX按优先级顺序排在dx_URG之前。


这是我以为您想填写 next 诊断而不是 last 诊断的原始解决方案。它对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      

几个数据说明。在您的代码中,第5行的年份为2008,但是在表中,您的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)

答案 1 :(得分:0)

这是一个很有趣的问题,并提出了基于data.table的{​​{1}}解决方案:

dplyr::case_when()