Создание новой переменной из условной операции над 3 старыми переменными в R - PullRequest
1 голос
/ 12 января 2010

У меня есть набор данных в 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 ]

3 голосов
/ 12 января 2010

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

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

и т.д.

"в пределах" просто экономит немного времени.

2 голосов
/ 12 января 2010

Прежде всего, было бы неплохо, если вместо character используется вектор logical, тогда вы можете написать Control вместо Control == "TRUE" и !Control вместо Control == "FALSE". И ваш код будет короче.

Для вашей задачи я буду использовать несколько 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]

Это хороший трюк, когда вам нужно декодировать несколько логических столбцов в символ.

1 голос
/ 12 января 2010

Использование преобразования делает это компактным и элегантным:

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

В качестве альтернативы, основываясь на версии Марека, мы можем использовать логические векторы для вычисления индекса немного более компактно:

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