【问题标题】:Dealing with NA and boolean sums in R在 R 中处理 NA 和布尔和
【发布时间】:2019-08-02 18:52:22
【问题描述】:

我正在尝试创建一个新变量,该变量涉及数值和逻辑(指标)的乘积之和,但最终结果没有意义。

数据

我已生成以下数据集作为我遇到的问题的最小可重现示例。每行都是一个个体,mJSW_BLmJSW_12mJSW_24mJSW_36 列是基线的测量值,12、24 和 36。我创建的最后一个变量 JSNCASE_TP 表示第一个个人符合病例定义的时间(12、24 或 36)(从基线减少 0.7)。 JSNCASE_TP 的计算应该忽略 NA 值,可以取值 0、12、24 或 36。

require(dplyr)

set.seed(1)
N = 10
mJSW_BL <- runif(N,0.1,2)
mJSW_12 <- runif(N,0.1,2)
mJSW_24 <- runif(N,0.1,2)
mJSW_36 <- runif(N,0.1,2)

#Randomly set some values to NA
mJSW_12[sample(N,2)] <- NA
mJSW_36[sample(N,1)] <- NA

#Create dataframe
df <- data.frame(mJSW_BL,mJSW_12,mJSW_24,mJSW_36)

df2 <- df %>%
       #Create variables indicating decrease from BL
       mutate(mJSW_BLto12 = mJSW_BL - mJSW_12,
              mJSW_BLto24 = mJSW_BL - mJSW_24,
              mJSW_BLto36 = mJSW_BL - mJSW_36) %>%
       #JSN case - decrease by 0.7 from BL
       mutate(JSNCASE_12 = (mJSW_BLto12>=0.7),
              JSNCASE_24 = (mJSW_BLto24>=0.7),
              JSNCASE_36 = (mJSW_BLto36>=0.7)) %>%
       #Which timepoint did JSN first occur?
       mutate(JSNCASE_TP = sum(12*JSNCASE_12, 
                               24*(JSNCASE_24 & !JSNCASE_12),
                               36*(JSNCASE_36 & !(JSNCASE_12 | JSNCASE_24)),
                               na.rm=TRUE))    

问题

在数据df2中,以第4行为例,其中JSNCASE_12JSNCASE_24JSNCASE_36都是TRUE,但JSNCASE_TP=36。应该是JSNCASE_TP=12。此外,取第 6 行,其中JSNCASE_12=NAJSNCASE_24=TRUEJSNCASE_36=FALSE。我应该得到JSNCASE_TP=24。也许我错过了一些基本的东西,但我尝试了几种方法并没有产生预期的结果。 10 行的JSNCASE_TP 的值应为0,0,0,12,0,24,24,0,0,0

编辑 感谢@Dave2e 的 cmets,下面的代码可以正常工作:

df2 <- df %>%
   #Create variables indicating decrease from BL
   mutate(mJSW_BLto12 = mJSW_BL - mJSW_12,
          mJSW_BLto24 = mJSW_BL - mJSW_24,
          mJSW_BLto36 = mJSW_BL - mJSW_36) %>%
   #JSN case - decrease by 0.7 from BL
   mutate(JSNCASE_12 = (mJSW_BLto12>=0.7),
          JSNCASE_24 = (mJSW_BLto24>=0.7),
          JSNCASE_36 = (mJSW_BLto36>=0.7)) %>%
   rowwise() %>%
   #Which timepoint did JSN first occur?
   mutate(JSNCASE_TP = sum(12*JSNCASE_12, 
                           24*(JSNCASE_24 & (!JSNCASE_12| is.na(JSNCASE_12))),
                           36*(JSNCASE_36 & ((!JSNCASE_12 | is.na(JSNCASE_12)) & 
                                             (!JSNCASE_24 | is.na(JSNCASE_24)))),
                           na.rm=TRUE))    

【问题讨论】:

  • 您对sum 的使用不正确。该函数将所有三个向量组合并返回一个总计。您需要明智地执行求和行。
  • 谢谢。一旦我在最后一个mutate 之前添加“rowwise() %>%”,这就会关闭。但是,我仍然无法获得 JSNCASE_TP 的第一个“24”(第 6 行),因为总和计算结果为 (FALSE &amp; !(NA | TRUE)),输出 0。
  • 这可能适用于其他情况:24*(df2$JSNCASE_24 &amp; (!JSNCASE_12| is.na(JSNCASE_12)))
  • 知道了!谢谢!

标签: r dplyr boolean na


【解决方案1】:

将 NA 与 TRUE/FALSE 混合在一起确实会使事情复杂化。

这是一个使用 apply 函数的 hack。基本上找到其中包含 TRUE 的第一列,然后乘以 12 以获得正确的时间。由于可能所有列都为 FALSE,因此需要检查和处理 min 函数返回 inf 值的情况。

df2 <- df %>%
  #Create variables indicating decrease from BL
  mutate(mJSW_BLto12 = mJSW_BL - mJSW_12,
         mJSW_BLto24 = mJSW_BL - mJSW_24,
         mJSW_BLto36 = mJSW_BL - mJSW_36) %>%
  #JSN case - decrease by 0.7 from BL
  mutate(JSNCASE_12 = (mJSW_BLto12>=0.7),
         JSNCASE_24 = (mJSW_BLto24>=0.7),
         JSNCASE_36 = (mJSW_BLto36>=0.7))


df2$JSNCASE_TP<-12*apply(df2[,8:10], 1, function(x){ ifelse(is.infinite(min(which(x==TRUE))), 0, min(which(x==TRUE)) )})

我确定有可能的 dplyr 版本。

【讨论】:

    【解决方案2】:

    我们可以使用mutate_atapply获取列名,如果存在则为0。

    library(dplyr)
    df %>% 
      mutate_at(vars(matches('.*_\\d+')), list(ind=~mJSW_BL-.>=0.7)) %>% 
      mutate(JSNCASE_TP = apply(.[grepl('.*_ind',names(.))], 1, function(x){
                                 x <- x[!is.na(x)]
                                 ifelse(all(!x), 0, names(x)[which.max(x)])
    }))
    
         mJSW_BL   mJSW_12   mJSW_24   mJSW_36 mJSW_12_ind mJSW_24_ind mJSW_36_ind  JSNCASE_TP
    1  0.6044665 0.4913517 1.8759399 1.0159522       FALSE       FALSE       FALSE           0
    2  0.8070354 0.4354578 0.5030708 1.2391751       FALSE       FALSE       FALSE           0
    3  1.1884214 1.4053434 1.3381802 1.0377285       FALSE       FALSE       FALSE           0
    4  1.8255948 0.8297971 0.3385547 0.4538134        TRUE        TRUE        TRUE mJSW_12_ind
    5  0.4831957 1.5626987 0.6077193 1.6720093       FALSE       FALSE       FALSE           0
    6  1.8069404        NA 0.8336168 1.3700868          NA        TRUE       FALSE mJSW_24_ind
    7  1.8948830 1.4634752 0.1254416 1.6090557       FALSE        TRUE       FALSE mJSW_24_ind
    8  1.3555158 1.9846216 0.8265371        NA       FALSE       FALSE          NA           0
    9  1.2953167        NA 1.7524126 1.4750508          NA       FALSE       FALSE           0
    10 0.2173939 1.5771459 0.7466631 0.8814214       FALSE       FALSE       FALSE           0
    

    但是,最好将您的数据传输到tidy data,进行分析,然后再传输回宽格式。这是一种方法

    library(dplyr)
    library(tidyr)
    df %>% rownames_to_column(var = 'id') %>% 
      gather(key,value,-id) %>% 
      group_by(id) %>% 
      mutate(Ind = ifelse(is.na(value), FALSE, (first(value)-value)>=0.7), JSNCASE_TP = ifelse(any(Ind),key[Ind],'0')) %>% 
      select(-Ind) %>% ungroup() %>% 
      spread(key, value) %>% 
      arrange(as.numeric(id))
    

    【讨论】:

      猜你喜欢
      • 2020-01-25
      • 2012-09-21
      • 2012-07-17
      • 1970-01-01
      • 2011-01-17
      • 1970-01-01
      • 2017-06-23
      • 2017-04-17
      • 1970-01-01
      相关资源
      最近更新 更多