2014-09-16 15 views
5

prendere questi dati di esempio:Ottenere Valore dell'ultimo colonna non vuota per ogni riga

data.frame(a_1=c("Apple","Grapes","Melon","Peach"),a_2=c("Nuts","Kiwi","Lime","Honey"),a_3=c("Plum","Apple",NA,NA),a_4=c("Cucumber",NA,NA,NA)) 

    a_1 a_2 a_3  a_4 
1 Apple Nuts Plum Cucumber 
2 Grapes Kiwi Apple <NA> 
3 Melon Lime <NA>  <NA> 
4 Peach Honey <NA> <NA> 

Fondamentalmente voglio eseguire un grep su l'ultima colonna di ogni riga che non è NA. Così la mia x in grep ("modello", x) dovrebbe essere:

Cucumber 
Apple 
Lime 
Honey 

ho un intero che mi dice che a_n è l'ultimo:

numcol <- rowSums(!is.na(df[,grep("(^a_)\\d", colnames(df))])) 

Finora ho provato qualcosa di simile questo in combinazione con ave(), si applica() e dplyr:

grepl("pattern",df[,sprintf("a_%i",numcol)]) 

Tuttavia io non abbastanza può farlo funzionare. Tieni presente che il mio set di dati è molto grande, quindi speravo di ottenere una soluzione vettoriale o mb dplyr. L'aiuto sarebbe molto apprezzato.

/e: Grazie, questa è davvero una buona soluzione. Il mio pensiero era troppo complicato. (l'espressione regolare è dovuta ai miei dati più specifici)

risposta

8

Non c'è bisogno di regex qui. Basta usare apply + tail + na.omit:

> apply(mydf, 1, function(x) tail(na.omit(x), 1)) 
[1] "Cucumber" "Apple" "Lime"  "Honey" 

non so come questo confronto in termini di velocità, ma si È inoltre possibile utilizzare una combinazione di "data.table" e "reshape2 ", in questo modo:

library(data.table) 
library(reshape2) 
na.omit(melt(as.data.table(mydf, keep.rownames = TRUE), 
      id.vars = "rn"))[, value[.N], by = rn] 
# rn  V1 
# 1: 1 Cucumber 
# 2: 2 Apple 
# 3: 3  Lime 
# 4: 4 Honey 

O, ancora meglio:

melt(as.data.table(df, keep.rownames = TRUE), 
    id.vars = "rn", na.rm = TRUE)[, value[.N], by = rn] 
# rn  V1 
# 1: 1 Cucumber 
# 2: 2 Apple 
# 3: 3  Lime 
# 4: 4 Honey 

Questo sarebbe molto più veloce. Su un set di dati di 800k righe, apply ha richiesto ~50 secondi mentre l'approccio data.table ha richiesto circa 2,5 secondi.

0

Si potrebbe anche provare: (df1 è l'insieme di dati)

indx <- which(!is.na(df1), arr.ind=TRUE) 
df1[cbind(1:nrow(df1),tapply(indx[,2], indx[,1], FUN=max))] 
#[1] "Cucumber" "Apple" "Lime"  "Honey" 
3

Un'altra alternativa che potrebbe essere abbastanza veloce:

DF[cbind(seq_len(nrow(DF)), max.col(!is.na(DF), "last"))] 
#[1] "Cucumber" "Apple" "Lime"  "Honey" 

Dove "DF":

DF = structure(list(a_1 = structure(1:4, .Label = c("Apple", "Grapes", 
"Melon", "Peach"), class = "factor"), a_2 = structure(c(4L, 2L, 
3L, 1L), .Label = c("Honey", "Kiwi", "Lime", "Nuts"), class = "factor"), 
    a_3 = structure(c(2L, 1L, NA, NA), .Label = c("Apple", "Plum" 
    ), class = "factor"), a_4 = structure(c(1L, NA, NA, NA), .Label = "Cucumber", class = "factor")), .Names = c("a_1", 
"a_2", "a_3", "a_4"), row.names = c(NA, -4L), class = "data.frame") 
+0

+1 In realtà stavo cercando 'max.col', ho dimenticato il nome. – akrun

Problemi correlati