Я написал пакет R, который использует селекторы {tidyselect} (например, contains()
, starts_with()
и т. д.). Я хотел бы добавить в пакет еще несколько вспомогательных функций выбора для выбора переменных на основе какого-либо атрибута. Например, выберите все числовые переменные или, возможно, все логические переменные.
Я просмотрел базовый код {tidyselect}. Но я не могу предположить, как работает регистрация переменных, и поэтому не могу расширить ее для выбора переменных по их атрибутам.
Я провел некоторый поиск, и похоже, что пакет {recipes} успешно реализовал дополнительные помощники, которые я ищу (например, all_numeric()
), но я изо всех сил пытаюсь написать функции расширения самостоятельно. https://github.com/tidymodels/recipes/blob/master/R/selections.R
Я считаю, что это сводится к тому, что я не понимаю, что происходит, когда переменные регистрируются с помощью функции tidyselect::scoped_vars()
. Если я запускаю tidyselect::scoped_vars(vars = names(mtcars))
в чистой среде, я не вижу никаких изменений. Но я могу использовать помощники {tidyselect} в глобальной среде после регистрации переменных.
names(mtcars)
#> [1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear"
#> [11] "carb"
tidyselect::scoped_vars(vars = names(mtcars))
# returns position of column 'mpg'
tidyselect::starts_with("mp")
#> 1
Любые подсказки или направление к некоторой документации будут БОЛЬШИМ образом оценены! Спасибо!
Когда вы вызываете scoped_vars()
, данные имена переменных сохраняются во внутренней среде на время текущего вызова функции:
(function() {
print(tidyselect:::vars_env$selected)
tidyselect::scoped_vars(names(mtcars))
print(tidyselect:::vars_env$selected)
})()
#> NULL
#> [1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear"
#> [11] "carb"
print(tidyselect:::vars_env$selected)
#> NULL
Насколько я могу судить, это единственная информация, которую {tidyselect} хранит о переменных; поэтому, если вы хотите выбирать на основе атрибутов, вы должны сами поддерживать информацию об атрибутах. Это также то, что делает {recipes} с cur_info_env
окружающая среда.
Грубая реализация может выглядеть примерно так:
type_env <- rlang::new_environment()
select_with_attributes <- function(.data, ...) {
type_env$types <- purrr::map(.data, class)
dplyr::select(.data, ...)
}
all_numeric <- function() {
which(purrr::map_lgl(type_env$types, ~ any(.x %in% "numeric")))
}
head(select_with_attributes(iris, all_numeric()))
#> Sepal.Length Sepal.Width Petal.Length Petal.Width
#> 1 5.1 3.5 1.4 0.2
#> 2 4.9 3.0 1.4 0.2
#> 3 4.7 3.2 1.3 0.2
#> 4 4.6 3.1 1.5 0.2
#> 5 5.0 3.6 1.4 0.2
#> 6 5.4 3.9 1.7 0.4
Created on 2019-06-13 by the reprex package (v0.2.1)
Он создает ловушку в среде (проверьте аргумент
frame
), которую позже можно вызвать с помощьюtidyselect::peek_vars
(перенаправляет на env, например,tidyselect:::vars_env
).