Проблема
У меня есть эта функция, которая мне нужна, чтобы она работала быстрее:)
if (length(vec) == 0) { # first case
count = sum(apply(df, 1, function(x) {
all(x == 0, na.rm = T)
}))
} else if (length(vec) == 1) { # second case
count = sum(df[, vec], na.rm = T)
} else {
count = sum(apply(df[, vec], 1, function(x) { # third case
all(x == 1) }), na.rm = T)
}
df
- это data.frame
с только 1, 0 илиNA значения . vec
является подвектором colnames(df)
.
- Первый случай : подсчитать строки thta после удаления NA, они имеют только 0 (или ничего -например, в строке были только NA - вы тоже это учитываете)
- Второй случай : подсчитать 1 в векторе (выбран только 1 столбец) после удаления NA
- Третий случай : из отфильтрованного data.frame получите количество строк, у которых все значения равны 1.
Вопрос
Есть ли какой-либо способ, которым вы думаетечто может заставить этот код работать быстрее, используя dplyr
или что-то еще, поскольку он манипулирует данными кадр за строкой? Например, когда я поменял более простой вариант (2-й случай) - count = sum(df[, vec], na.rm = T)
на dplyr
: sum(df %>% select(vec), na.rm = T)
и выполнил тест, это было значительно хуже (но хорошо, я не думаю, что 2-й случай может быть значительно быстрее с любымметод).
Приветствуются любые подсказки или уловки для 2-го и 3-го случаев!
Сравнительный анализ
Достаточно большой фрейм data.frame для игры: df = matrix(data = sample(c(0,1,NA), size = 100000, replace = TRUE), nrow = 10000, ncol = 10)
.
rbenchmark::benchmark("prev" = {sum(apply(df, 1, function(x) {all(x == 0, na.rm = T)}))}, "new-long" = {sum((rowSums(df == 0, na.rm = TRUE) + rowSums(is.na(df)) == ncol(df)))}, "new-short" = {sum(!rowSums(df != 0, na.rm = TRUE))}, replications = 1000, columns = c("test", "replications", "elapsed", "relative", "user.self", "sys.self"))
Результаты :
test replications elapsed relative user.self sys.self
2 new-long 1000 1.267 1.412 1.267 0
3 new-short 1000 0.897 1.000 0.897 0
1 prev 1000 11.857 13.219 11.859 0
- третий случай (например,
vec = 1:5
):
rbenchmark::benchmark("prev" = {sum(apply(df[, vec], 1, function(x) { all(x == 1) }), na.rm = T)}, "new" = {sum(!rowSums(replace(df[, vec], is.na(df[, vec]), -999) != 1))}, replications = 1000, columns = c("test", "replications", "elapsed", "relative", "user.self", "sys.self"))
Результаты :
test replications elapsed relative user.self sys.self
2 new 1000 0.179 1.000 0.175 0.004
1 prev 1000 2.219 12.397 2.219 0.000
В целом, приятноускорение с использованием rowSums
! Используйте это тоже вместо apply
!