我在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)
关于如何简化和缩短此代码的任何想法都将非常感激,因为我必须对我的数据库做很多这样的事情。
非常感谢, 艾米
答案 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])]})