2014-09-16 3 views
5

Возьмите этот образец данных:Получить значение последнего непустого столбца для каждой строки

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> 

В основном я хочу, чтобы запустить Grep на последнем столбце каждой строки, которая не является NA. Таким образом, мой х в Grep («шаблон», х) должно быть:

Cucumber 
Apple 
Lime 
Honey 

У меня есть целое число, которое говорит мне, который a_N является последним:

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

До сих пор я пытался что-то вроде это в сочетании с ave(), apply() и dplyr:

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

Однако я не могу заставить его работать. Имейте в виду, что мой набор данных очень велик, поэтому я надеялся, что это будет векторное решение или mb dplyr. Помощь была бы принята с благодарностью.

/e: Спасибо, это действительно хорошее решение. Мое мышление было слишком сложным. (регулярное выражение связано с моими более конкретными данными)

ответ

8

Здесь нет необходимости в регулярном выражении. Просто используйте apply + tail + na.omit:

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

Я не знаю, как это сравнивается с точки зрения скорости, но вы Вы также можете использовать комбинацию «data.table» и «reshape2 », как это:

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 

Или еще лучше:

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 

Это будет много быстрее. В наборе данных 800 тыс. Строк apply занял около 50 секунд, а подход data.table занял около 2,5 секунд.

0

Вы также можете попробовать: (df1 является набором данных)

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

Другой вариант, который может быть довольно быстро:

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

Где "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 На самом деле я искал 'max.col', забыл имя. – akrun

Смежные вопросы