Подмножества строк со всеми/любыми столбцами, большими, чем определенное значение
С
df <- data.frame(id=c(1:5), v1=c(0,15,9,12,7), v2=c(9,32,6,17,11))
Как я могу извлекать строки со значениями для ВСЕХ столбцов больше 10, которые должны возвращаться:
id v1 v2
2 2 15 32
4 4 12 17
И что, если в ЛЮБОМ столбце больше 10:
id v1 v2
2 2 15 32
4 4 12 17
5 5 7 11
Ответы
Ответ 1
См. функции all()
и any()
для первой и второй частей ваших вопросов соответственно. Функция apply()
может использоваться для запуска функций по строкам или столбцам. (MARGIN = 1
- строки, MARGIN = 2
- столбцы и т.д.). Примечание. Я использую apply()
в df[, -1]
, чтобы игнорировать переменную id
при выполнении сравнений.
Часть 1:
> df <- data.frame(id=c(1:5), v1=c(0,15,9,12,7), v2=c(9,32,6,17,11))
> df[apply(df[, -1], MARGIN = 1, function(x) all(x > 10)), ]
id v1 v2
2 2 15 32
4 4 12 17
Часть 2:
> df[apply(df[, -1], MARGIN = 1, function(x) any(x > 10)), ]
id v1 v2
2 2 15 32
4 4 12 17
5 5 7 11
Чтобы узнать, что происходит, x > 10
возвращает логический вектор для каждой строки (через apply()
указывает, будет ли каждый элемент больше 10. all()
возвращает TRUE
, если все элементы входного вектора TRUE
и FALSE
в противном случае. any()
возвращает TRUE
, если любой из элементов на входе TRUE
и FALSE
, если все они FALSE
.
Затем я использую логический вектор, полученный в результате вызова apply()
> apply(df[, -1], MARGIN = 1, function(x) all(x > 10))
[1] FALSE TRUE FALSE TRUE FALSE
> apply(df[, -1], MARGIN = 1, function(x) any(x > 10))
[1] FALSE TRUE FALSE TRUE TRUE
подмножество df
(как показано выше).
Ответ 2
Это можно сделать, используя apply
с полем 1, который будет применять функцию к каждой строке. Функция проверки данной строки будет
function(row) {all(row > 10)}
Таким образом, способ извлечь сами строки -
df[apply(df, 1, function(row) {all(row > 10)}),]
Ответ 3
Один из вариантов - циклическая последовательность строк (например, с apply
) и использование any
или all
, как предложено в двух других ответах. Однако это может быть неэффективным для больших кадров данных.
Векторизованный подход состоял бы в том, чтобы использовать rowSums
для определения количества значений в каждой строке, соответствующей вашему критерию, и фильтра на основе этого.
При фильтрации в строки, где все по меньшей мере 10, это то же самое, что и фильтрация в случаях, когда число значений не более 10 равно 0:
df[rowSums(df[,-1] <= 10) == 0,]
# id v1 v2
# 2 2 15 32
# 4 4 12 17
Аналогично, rowSums
можно легко использовать для вычисления строк с чем-либо, превышающим 10:
df[rowSums(df[,-1] > 10) > 0,]
# id v1 v2
# 2 2 15 32
# 4 4 12 17
# 5 5 7 11
Ускорение выполняется с большим входом:
set.seed(144)
df <- matrix(sample(c(1, 10, 20), 3e6, replace=TRUE), ncol=3)
system.time(df[apply(df[, -1], MARGIN = 1, function(x) all(x > 10)), ])
# user system elapsed
# 1.754 0.156 2.102
system.time(df[rowSums(df[,-1] <= 10) == 0,])
# user system elapsed
# 0.04 0.01 0.05