从R中3个旧变量的条件运算创建一个新变量

时间:2010-01-12 07:55:32

标签: r variables conditional

我在R中有一个数据集,其中包含快速诊断测试的结果。如果测试工作正常(对照线),并且检测到的两种寄生虫物种中的每一种都有可见线,如果它们存在于患者样本中,则该测试具有可见线。

数据集包含每个测试行的逻辑列,如下所示: (数据库称为RDTbase)

   Control  Pf    Pv
1. TRUE     TRUE  FALSE
2. TRUE     FALSE TRUE
3. FALSE    FALSE FALSE
4. TRUE     TRUE  TRUE
5. TRUE     FALSE FALSE

我想添加一个新列,其中包含每个快速测试的单个结果。根据三条线所满足的不同逻辑条件指定结果。对于上面的示例,新列将如下所示:

Control  Pf     Pv     Result
1. TRUE  TRUE   FALSE  Pf
2. TRUE  FALSE  TRUE   Pv
3. FALSE FALSE  FALSE  Invalid
4. TRUE  TRUE   TRUE   Mixed
5. TRUE  FALSE  FALSE  Negative

我能够创建新列,但需要大量编码,我认为必须有一种更简单(更短)的方法。

这是我当前的(长)方法:

R.Pf <- RDTbase[which(Control == "TRUE" & Pf == "TRUE" & Pv == "FALSE"),]
R.Pv <- RDTbase[which(Control == "TRUE" & Pf == "FALSE" & Pv == "TRUE"),]
R.inv <- RDTbase[which(Control == "FALSE"),]
R.mix <- RDTbase[which(Control == "TRUE" & Pf == "TRUE" & Pv == "TRUE"),]
R.neg <- RDTbase[which(Control == "TRUE" & Pf == "FALSE" & Pv == "FALSE"),]

R.Pf$Result <- c("Pf")
R.Pv$Result <- c("Pv")
R.inv$Result <- c("Invalid")
R.mix$Result <- c("Mixed")
R.neg$Result <- c("Negative")

RDTbase2 <- rbind(R.Pf, R.Pv, R.inv, R.mix, R.neg)

关于如何简化和缩短此代码的任何想法都将非常感激,因为我必须对我的数据库做很多这样的事情。

非常感谢, 艾米

3 个答案:

答案 0 :(得分:3)

我只是创建数据框的另一列并有条件地分配给它的不同子集。您还可以减少数据帧索引代码。

RDTbase$Result = NA 
RDTbase <- within(RDTbase, Result[Control=="TRUE" & Pf=="TRUE" & Pv=="FALSE"] <- "Pf")
RDTbase <- within(RDTbase, Result[Control=="FALSE"] <- "Invalid")

“内”只是节省一点点打字。

答案 1 :(得分:2)

首先,当你使用logical向量代替character时会更好,然后你可以代替Control代替Control == "TRUE"!Control代替Control == "FALSE" 1}}。而且你的代码会更短。

对于你的问题,我将使用几个ifelse

RDTbase$Result <- ifelse(
  Control == "TRUE",
  ifelse(
    Pf == "TRUE",
    ifelse(Pv == "TRUE","Mixed","Pf"), # when Control is TRUE, Pf is TRUE
    ifelse(Pv == "TRUE","Pv","Negative"), # when Control is TRUE, Pf is FALSE
  ),
  "Invalid" # when Control is FALSE
)

但我喜欢魔法技巧,所以你可以遵循:

num_code <- (
  as.numeric(as.logical(Control))
  + 2*as.numeric(as.logical(Pf))
  + 4*as.numeric(as.logical(Pv))
) # values are 0,1,2,...,7
# then 
RDTbase$Result <- c( 
  "Invalid" , # 0 = F,F,F # Control, Pf, Pv
  "Negative", # 1 = T,F,F
  "Invalid" , # 2 = F,T,F
  "Pf"      , # 3 = T,T,F
  "Invalid" , # 4 = F,F,T
  "Pv"      , # 5 = T,F,T
  "Invalid" , # 6 = F,T,T
  "Mixed"   , # 7 = T,T,T
)[num_code+1]

当您需要将多个逻辑列解码为字符时,这是一个很好的技巧。

答案 2 :(得分:1)

使用变换使这个紧凑而优雅:

transform(a, Result = 
 ifelse(Control,
  ifelse(Pf, 
   ifelse(Pv, "Mixed", "Pf"),
   ifelse(Pv, "Pv", "Negative")),
  "Invalid"))

产量

  Control    Pf    Pv   Result
1    TRUE  TRUE FALSE       Pf
2    TRUE FALSE  TRUE       Pv
3   FALSE FALSE FALSE  Invalid
4    TRUE  TRUE  TRUE    Mixed
5    TRUE FALSE FALSE Negative

或者,在Marek版本的基础上,我们可以使用逻辑向量来更紧凑地计算指数:

a$Result = apply(a,1,
  function(x){
    c(rep("Invalid", 4), "Negative", "Pv", "Pf", "Mixed")
      [1+sum(c(4,2,1)[x])]})