2016-06-22 3 views
4

Мне нужно подмножить таблицу данных на основе условия для нескольких столбцов, а затем выполнить операцию над результатом.Поиск R в нескольких столбцах данных

Минимальный пример с простым data.table:

x <- data.table(id=c(1, 2, 3, 4), colour1 = c('red', 'green', 'green', 'blue'), 
       colour2 = c('yellow', 'red', 'blue', 'black'), 
       colour3 = c('blue', 'black', 'red', 'yellow'), 
       score = c(0.7, 0.9, 0.2, 0.35)) 

я тогда хочу найти максимальное количество баллов для любой строки, которая содержит цвет «желтый»:

max_score <- max(x[colour1 == 'yellow' | colour2 == 'yellow' | colour3 == 'yellow']$score) 

В этом примере , приведенный выше код работает нормально, но есть ли лучший способ проверить это условие на нескольких столбцах? На практике таблица будет намного больше, и количество столбцов может измениться, поэтому я хотел бы сделать это динамически.

+0

Связанное почти дублирующее сообщение: http://stackoverflow.com/questions/18589595/filter-rows-based-on-multiple-column-conditions-r – zx8754

ответ

7

Он может чувствовать себя трудно, потому что ваши данные в широком (т.е. "неопрятный") формат. Просто конвертируйте в длинный формат, используя melt, и это очень просто.

melt(x, measure.vars = grep("^colo", names(x)))[,max(score[value == "yellow"])] 
# [1] 0.7 

или

melt(x, measure.vars = grep("^colo", names(x)))[value == "yellow", max(score)] 

Чтобы понять, что происходит, это запустить первый

melt(x, measure.vars = grep("^colo", names(x))) 

, а затем вся команда.


Конечно, вы можете сделать это в два этапа тоже, в случае, если вы хотите сохранить длинный формат для дальнейших расчетов:

x_tidy <- melt(x, measure.vars = grep("^colo", names(x))) 
x_tidy[value == "yellow", max(score)] 
#[1] 0.7 
2

Использование rowSums:

max(
    x[ rowSums(x[, grepl("colour", colnames(x)), with = FALSE] == "yellow") > 0, 
    "score", with = FALSE] 
) 
1

Использование R computing on the language функции.

i.cols.equal <- function(cols, value) { 
    l <- lapply(cols, function(col) call("==", as.name(col), value)) 
    Reduce(function(a, b) bquote(.(a) | .(b)), l) 
} 
ii <- i.cols.equal(cols=c("colour1", "colour2", "colour3"), value="yellow") 
print(ii) 
#colour1 == "yellow" | colour2 == "yellow" | colour3 == "yellow" 
x[eval(ii), max(score)] 
#[1] 0.7 
1

с нативным R

y=data.frame(x) 
max(y$score[apply(y[,grep("^colo", colnames(y))]=="yellow",1,any)]) 

[1] 0.7 
1

Другой идеей, похоже на jangorecki лет (вероятно, более простой), это просто цикл через колонку накопление "логический" вектор строк для проверки на max в x[["score"]] для экономии использования памяти:

i = logical(nrow(x)) 
for(j in which(startsWith(names(x), "colour"))) i = i | x[[j]] == "yellow" 
max(x[["score"]][i]) 
#[1] 0.7 
Смежные вопросы