Быстрая проверка для каждой строки в data.table, если определенные столбцы соответствуют критерию

Я просто не могу обойти эту довольно простую задачу, и чтение на связанных с этим проблемах на этом сайте не помогло.

Я создал минимальный пример:

a <- data.table(n = c("case1", "case2", "case3"), x = c(0,2,5), y = c(1,1,4), z = c(1,1,0))
cols <- c("x", "y", "z")
a
       n x y z
1: case1 0 1 1
2: case2 2 1 1
3: case3 5 4 0

Все, что я хочу сделать, это выбрать все строки из a, если все значения в столбцах, имена которых сохранены в cols, находятся выше 0.

Так что я хочу получить в этом случае:

       n x y z
2: case2 2 1 1

Я применил в сочетании с all(), но я думаю, что для data.table существует гораздо более быстрый способ сделать это. Мои исходные данные, конечно, намного больше, а cols содержит 80 имен столбцов. Спасибо за вашу помощь!

=== РЕДАКТИРОВАТЬ ===

Спасибо за ваши ответы! Все они работают, но, очевидно, с разной производительностью. Пожалуйста, проверьте комментарии принятого ответа для теста. Самый быстрый способ сделать это, действительно:

a[ a[, do.call(pmin, .SD) > 0, .SDcols=cols] ]

Я также реплицировал тесты для различных решений с использованием пакета rbenchmark и моего исходного набора данных с немного разными параметрами (880 000 строк, 64 столбца, из которых 62 выбраны) и может подтвердить ранжирование скорости для разных решений (10 репликаций имеют были сделаны):

z[z[, !Reduce(`+`, lapply(.SD, `<`, 11)),.SDcols = col.names]]: 3,32 с

z[apply(z[, col.names, with = FALSE], 1, function(x) all(x>10))]: 37,41 с

z[ z[, do.call(pmin, .SD) > 10, .SDcols=col.names] ]: 2,03 с

z[rowSums(z[, lapply(.SD, `<`, 11), .SDcols=col.names])==0]: 4.84 с

Снова: Спасибо!

Ответ 1

Мы можем использовать Reduce с .SDcols. Задайте интересующие столбцы в .SDcols, перейдем к подмножеству Data.table(.SD), проверьте, равно ли оно 0, получите сумму каждой строки с помощью Reduce, negate (!), чтобы получить логический вектор, который возвращает TRUE, когда нет 0 элементов, и использовать это для подмножества строк 'a'

a[a[, !Reduce(`+`, lapply(.SD, `<=`, 0)),.SDcols = cols]]
#       n x y z
#1: case2 2 1 1

Или как @Frank, упомянутый в комментариях, pmin также может использоваться

a[a[, do.call(pmin, .SD), .SDcols = cols]>0]

Ответ 2

Вы можете попробовать

a[rowSums(a[, lapply(.SD, `<=`, 0), .SDcols=cols])==0]
#       n x y z
#1: case2 2 1 1

Он выбирает строки, для которых нет столбцов cols со значением ниже или равным нулю (вы также можете использовать условие x > 0 и, если хотите, выбрать ==length(cols)).

Ответ 3

Вы можете apply по строке, а затем проверить, если all значения в этой строке больше 0.

a[apply(a[, cols, with = FALSE], 1, function(x) all(x>0))]

#       n x y z
#1: case2 2 1 1