2014-09-16 12 views
5

Weź te dane przykładowe:uzyskać wartość ostatniego niepustego kolumny dla każdego wiersza

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> 

Zasadniczo chcę uruchomić grep na ostatniej kolumnie każdego wiersza, który nie jest na. Tak więc moja xw grep („wzór”, x) powinno być:

Cucumber 
Apple 
Lime 
Honey 

mam liczbą całkowitą, która mówi mi, który a_n jest ostatni:

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

Do tej pory próbowałem coś podobnego to w połączeniu z ave(), apply() i dplyr:

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

Jednak nie mogę tego zrobić. Należy pamiętać, że mój zbiór danych jest bardzo duży, więc miałem nadzieję, że to wektoryzowane rozwiązanie lub mb dplyr. Pomoc byłaby bardzo ceniona.

/e: Dzięki, to naprawdę dobre rozwiązanie. Moje myślenie było zbyt skomplikowane. (Wyjaśnienie wynika z moich bardziej szczegółowych danych)

Odpowiedz

8

Nie ma potrzeby stosowania tutaj wyrażeń regularnych. Wystarczy użyć apply + tail + na.omit:

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

Nie wiem, jak to porównuje pod względem szybkości, ale Można również użyć kombinacji „data.table” i „reshape2 ”coś takiego:

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 

Albo jeszcze lepiej:

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 

To byłby znacznie szybszy. W zestawie danych o 800 tys. Wierszy, apply zajęło około 50 sekund, podczas gdy podejście data.table zajęło około 2,5 sekundy.

0

Można też spróbować: (df1 jest zbiór danych)

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

Inna alternatywa to może być dość szybko:

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

Gdzie "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 Właściwie szukałem 'max.col', zapomniałem nazwy. – akrun

Powiązane problemy