2015-05-06 4 views
8

EDIT: Dies ist ein Betrogen von How to implement coalesce efficiently in R, vereinbart. Ich wusste nicht, dass mein Problem allgemeiner war als meine spezifische Anwendung, daher war diese Diskussion großartig.geschachtelt ifelse() ist das Schlimmste; Was ist das Beste?

Manchmal ist die Antwortvariable in einem randomisierten Experiment in einer anderen Spalte für jede experimentelle Gruppe enthalten (Y_1 bis Y_5 im folgenden Code). Es empfiehlt sich oft, die Antwortvariable in einer einzigen Spalte (Y_all) zu sammeln. Am Ende mache ich es wie im Beispiel unten. Aber ich bin sicher, es gibt einen besseren Weg. Gedanken?

set.seed(343) 
N <- 1000 
group <- sample(1:5, N, replace=TRUE) 
Y_1 <- ifelse(group==1, rbinom(sum(group==1), 1, .5), NA) 
Y_2 <- ifelse(group==2, rbinom(sum(group==2), 1, .5), NA) 
Y_3 <- ifelse(group==3, rbinom(sum(group==3), 1, .5), NA) 
Y_4 <- ifelse(group==4, rbinom(sum(group==4), 1, .5), NA) 
Y_5 <- ifelse(group==5, rbinom(sum(group==5), 1, .5), NA) 

## This is the part I want to make more efficient 
Y_all <- ifelse(!is.na(Y_1), Y_1, 
       ifelse(!is.na(Y_2), Y_2, 
         ifelse(!is.na(Y_3), Y_3, 
           ifelse(!is.na(Y_4), Y_4, 
            ifelse(!is.na(Y_5), Y_5, 
              NA))))) 

table(Y_all, Y_1, exclude = NULL) 
table(Y_all, Y_2, exclude = NULL) 
+3

Für diese spezielle Anwendung, der erste nicht fehlende Wert, der Name des SQL-Befehls ist 'coalesce', und es gibt eine sehr schöne Antwort von [Implementierung von SQL-Koaleszieren in R] (http://stackoverflow.com/q/19253820/903061). – Gregor

+0

Bitte verwenden Sie 'set.seed' – Frank

+0

Gregor, das ist genau das: Ich würde nie' Reduce' vorher finden. –

Antwort

5

Ich mag diesen Dann

#available from https://gist.github.com/MrFlick/10205794 
coalesce<-function(...) { 
    x<-lapply(list(...), function(z) {if (is.factor(z)) as.character(z) else z}) 
    m<-is.na(x[[1]]) 
    i<-2 
    while(any(m) & i<=length(x)) { 
     if (length(x[[i]])==length(x[[1]])) { 
      x[[1]][m]<-x[[i]][m] 
     } else if (length(x[[i]])==1) { 
      x[[1]][m]<-x[[i]] 
     } else { 
      stop(paste("length mismatch in argument",i," - found:", length(x[[i]]),"expected:",length(x[[1]]))) 
     } 
     m<-is.na(x[[1]]) 
     i<-i+1 
    } 
    return(x[[1]]) 
} 

eine coalesce() Funktion verwenden, können Sie

Y_all <- coalesce(Y_1,Y_2,Y_3,Y_4,Y_5) 

Natürlich tun, dies ist sehr spezifisch den ersten nicht-NA-Wert zu erhalten.

+0

Danke Mr. Flick - haben Sie eine Präferenz für diese Implementierung gegenüber denen in http://stackoverflow.com/questions/19253820/how-to-implement-coalesce-efficiently-in-r? –

+0

Nein. Sie müssen testen, um zu sehen, was in Ihrer speziellen Anwendung am besten ist. – MrFlick

+0

Diese Implementierung ist nett, weil es die Faktorumwandlung und die Fehlerbehandlung hat - die anderen sind noch nackter. – Gregor

2

denke ich, in diesem Fall, dass Sie die Schmelz Funktion können Sie die Daten zu lang-Format konvertieren und dann die Beseitigung der fehlenden Werte erhalten:

library(reshape2) 

set.seed(10) 
N <- 1000 
group <- sample(1:5, N, replace=TRUE) 
Y_1 <- ifelse(group==1, rbinom(sum(group==1), 1, .5), NA) 
Y_2 <- ifelse(group==2, rbinom(sum(group==2), 1, .5), NA) 
Y_3 <- ifelse(group==3, rbinom(sum(group==3), 1, .5), NA) 
Y_4 <- ifelse(group==4, rbinom(sum(group==4), 1, .5), NA) 
Y_5 <- ifelse(group==5, rbinom(sum(group==5), 1, .5), NA) 

Y_all = data.frame(group, Y_1, Y_2,Y_3,Y_4,Y_5) 

Y_all.m = melt(Y_all, id.var="group") 
Y_all.m = Y_all.m[!is.na(Y_all.m$value),] 
+0

Sollen 'identische (Y_all, Y_all.m $ value)' wahr sein? Es scheint, dass die Ergebnisse neu sortiert wurden, so dass dies nicht der Fall ist. Hm, dito für 'identical (Y_all, Y_all.m $ value [order (rownames (Y_all.m))]) ' – Frank

+0

Y_all.m ist eine lange Version von Y_all, also werden sie nicht identisch sein. Aber Sie können bestätigen, dass sie dieselben Werte haben: 'lapply (Y_all [, - 1], Tabelle, exclude = NULL); tapply (Y_all.m $ value, Y_all.m $ variable, Tabelle, exclude = NULL) '. – eipi10

+0

Gerade ist mir eingefallen, dass Sie auch tun können: 'identical (unname (unlist (Y_all [, - 1])), Y_all.m $ value)' (was 'TRUE' ergibt). – eipi10

1

Shop die Vektoren in einer Matrix und wählen Sie dann:

Ymat <- cbind(Y_1,Y_2,Y_3,Y_4,Y_5) 
mycol <- apply(!is.na(Ymat),1,which) 

Y_all.f <- Ymat[cbind(1:nrow(Ymat),mycol)] 

identical(Y_all,Y_all.f) # TRUE