2014-09-16 15 views
5

Đi dữ liệu mẫu này:Nhận Giá trị của cột không trống cuối cùng cho mỗi hàng

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> 

Về cơ bản tôi muốn chạy một grep trên cột cuối cùng của mỗi hàng mà không phải là NA. Do đó x của tôi trong grep ("mẫu", x) nên:

Cucumber 
Apple 
Lime 
Honey 

Tôi có một số nguyên mà nói với tôi mà a_N là mới nhất:

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

Cho đến nay tôi đã cố gắng một cái gì đó như điều này kết hợp với ave(), apply() và dplyr:

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

Tuy nhiên tôi không thể làm cho nó hoạt động được. Hãy nhớ rằng tập dữ liệu của tôi là rất lớn vì vậy tôi đã hy vọng vor một giải pháp vectorized hoặc mb dplyr. Trợ giúp sẽ được đánh giá cao.

/e: Cảm ơn, đó là giải pháp thực sự tốt. Suy nghĩ của tôi quá phức tạp. (regex là do dữ liệu cụ thể của tôi)

Trả lời

8

Không cần regex tại đây. Chỉ cần sử dụng apply + tail + na.omit:

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

Tôi không biết làm thế nào đây so sánh về tốc độ, nhưng bạn Bạn cũng có thể sử dụng một sự kết hợp của "data.table" và "reshape2 ", như thế này:

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 

Hoặc, thậm chí tốt hơn:

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 

Điều này sẽ là nhiều hơn nhanh hơn. Trên bộ dữ liệu 800k hàng, apply mất ~ 50 giây trong khi phương pháp tiếp cận data.table mất khoảng 2,5 giây.

0

Bạn cũng có thể thử: (df1 là bộ dữ liệu)

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

Một cách khác mà có thể khá nhanh:

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

đâu "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 Thực ra tôi đang tìm 'max.col', quên tên. – akrun

Các vấn đề liên quan