Мне повезло с векторизацией некоторых функций, что отлично подходит для чистого кода, избегания циклов и скорости.
Однако мне не удалось векторизовать какую-либо функцию, которая подмножает фрейм данных на основе входных данных функции.
Например. Эта функция хорошо работает, когда она получает элементы
test_funct <- function(sep_wid, sep_len) {
iris %>% filter(Sepal.Width > sep_wid & Sepal.Length < sep_len) %>% .$Petal.Width %>% sum
}
test_funct(4, 6)
# [1] 0.7 # This works nicely
Но при попытке предоставить векторы в качестве входных данных для этой функции:
sep_wid_vector <- c(4, 3.5, 3)
sep_len_vector <- c(6, 6, 6.5)
test_funct(sep_wid_vector, sep_len_vector)
[1] 9.1
Но желаемый результат — это вектор той же длины, что и входные векторы, как если бы функция запускалась над первыми элементами каждого вектора, затем над вторыми, затем над третьими. то есть
# 0.7 4.2 28.5
Для удобства здесь вывод, как если бы все они запускались отдельно.
test_funct(4, 6) # 0.7
test_funct(3.5, 6) # 4.2
test_funct(3, 6.5) # 28.5
Как я могу векторизовать функцию, которая подмножает данные на основе своих входных данных, чтобы она могла получать векторные входные данные?
Проблема в том, что filter
принимает векторные входные данные, поэтому он будет перерабатывать векторы в сравнениях Sepal.width
и Sepal.length
.
Один из способов сделать это — использовать map2
из пакета purrr
:
map2_dbl(sep_wid_vector, sep_len_vector, test_funct)
Конечно, вы могли бы обернуть это в функцию. Вы также можете рассмотреть возможность передачи фрейма данных в качестве параметра функции.
Вы можете использовать Vectorize
:
tv <- Vectorize(test_funct)
tv(sep_wid_vector, sep_len_vector)
# [1] 0.7 4.2 28.5
Это в основном обертка вокруг mapply
. Имейте в виду, что под капотом вы запускаете функцию *apply
, которая также является своего рода циклом.
Вот один из способов использования sapply
# function using sapply
test_funct <- function(sep_wid, sep_len) {
sapply(seq_along(sep_wid), function(x) {
sum(iris$Petal.Width[iris$Sepal.Width > sep_wid[x] & iris$Sepal.Length < sep_len[x]])
})
}
# testing with single value
test_funct(4,6)
[1] 0.7
# testing with vectors
test_funct(sep_wid_vector, sep_len_vector)
[1] 0.7 4.2 28.5
@thothal отличная находка с
purrr::map2_dbl
. Для полноты картины также работаетmapply(test_funct, sep_wid_vector, sep_len_vector)