2015-05-06 16 views
8

EDIT: questo è un dupe di How to implement coalesce efficiently in R, d'accordo. Non mi ero reso conto di quanto il mio problema fosse più generale della mia specifica applicazione, quindi questa discussione è stata grandiosa.ifelse annidato() è il peggiore; Qual è il miglior?

A volte, la variabile di risposta in un esperimento randomizzato è contenuta in una colonna diversa per ciascun gruppo sperimentale (da Y_1 a Y_5 nel seguente codice). Spesso è meglio raccogliere la variabile di risposta in una singola colonna (Y_all). Finisco per farlo come nell'esempio qui sotto. Ma sono sicuro che c'è un modo migliore. pensieri?

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

Per questa particolare applicazione, trovando il primo valore non mancante, il nome del comando SQL è 'coalesce', e c'è una bella risposta di [implementazione della coalesce di SQL in R] (http://stackoverflow.com/q/19253820/903 mila sessantauno). – Gregor

+0

Si prega di utilizzare 'set.seed' – Frank

+0

Gregor, questo è esattamente questo: non mi sarei mai imbattuto in' Reduce' prima. –

risposta

5

mi piace usare una funzione coalesce() per questo

#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]]) 
} 

Poi si può fare

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

Naturalmente, questo è molto specifico per ottenere il primo valore non-NA.

+0

Grazie Mr. Flick - avete una preferenza per questa implementazione rispetto a quelli in http://stackoverflow.com/questions/19253820/how-to-implement-coalesce-efficiently-in-r? –

+0

No. Dovresti testare per vedere cosa c'è di meglio nella tua particolare applicazione. – MrFlick

+0

Questa implementazione è piacevole perché ha un fattore di conversione e gestione degli errori --- gli altri sono ancora più semplici. – Gregor

2

Credo che in questo caso è possibile utilizzare la funzione di fusione per convertire i dati in formato lungo e poi sbarazzarsi dei valori mancanti:

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

Il valore 'identico (Y_all, Y_all.m $)' è vero? Sembra che i risultati siano stati riordinati in modo che non sia così. Hm, idem per 'identico (Y_all, Y_all.m $ valore [ordine (rownames (Y_all.m))])' – Frank

+0

Y_all.m è una versione lunga di Y_all, quindi non saranno identici. Ma puoi confermare che hanno gli stessi valori come questo: 'lapply (Y_all [, - 1], table, exclude = NULL); tapply (valore Y_all.m $, variabile Y_all.m $, tabella, exclude = NULL) '. – eipi10

+0

Mi è appena venuto in mente che puoi anche fare: 'identico (unnome (unlist (Y_all [, - 1])), Y_all.m $ valore)' (che produce 'TRUE'). – eipi10

1

Conservare i vettori in una matrice e quindi selezionare:

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 
Problemi correlati