#r #apply #sapply
#r #применить #sapply
Вопрос:
Здесь относительно новый пользователь R, который пытается сделать код более эффективным для будущего использования, в основном пробуя функции из семейства apply.
Прямо сейчас у меня есть скрипт, в котором я извлекаю средства из большого количества переменных (вручную), создавая список имен переменных и передавая его в sapply.
Итак, это пример того, как я составил список имен переменных и как я передал его в sapply
vars <- c("data$age", "data$gender", "data$PCLR")
means <- sapply(vars, fmean, data$group, na.rm=TRUE)
Однако теперь я хочу использовать функцию, которая использует формат аргумента function (varname, data), поэтому я не могу использовать тот список имен, который я создал. Что я пытаюсь сделать:
krusk <- sapply(vars, function(x) kruskal.test(x ~ group, data))
Я чувствую, что есть способ передать имена моих переменных в функции, которые я полностью игнорировал, вместо того, чтобы вручную создавать списки. У кого-нибудь есть какие-либо предложения?
Комментарии:
1. используется
reformulate
для преобразования строк в формулу:kruskal.test(reformulate('group', x), data)
Ответ №1:
Это может работать с использованием iris
dataset, data
аналогично замечательному предложению от @deschen:
#Vars
vars <- c("Sepal.Length", "Sepal.Width")
#Code
krusk <- sapply(vars, function(x) kruskal.test(iris[[x]] ~ iris[['Species']]))
Вывод:
krusk
Sepal.Length Sepal.Width
statistic 96.93744 63.57115
parameter 2 2
p.value 8.918734e-22 1.569282e-14
method "Kruskal-Wallis rank sum test" "Kruskal-Wallis rank sum test"
data.name "iris[[x]] by iris[["Species"]]" "iris[[x]] by iris[["Species"]]"
Комментарии:
1. Мой на самом деле не работал. Я также могу ошибаться, но я прочитал вопрос TOs таким образом, что требование к
vars
вектору по-прежнему будет заключаться в том, что он содержит объект данных имена, поэтому в вашем примереvars <- c("iris$Sepal.Length", "iris$Sepal.Width")
.
Ответ №2:
Вы были очень близки! Вы можете сделать это, установив фрейм данных, который вы вводите sapply
, используя свой vars
вектор, и изменив формулу в kruskal.test
:
vars <- c("Sepal.Length", "Sepal.Width")
sapply(iris[, vars], function(x) kruskal.test(x ~ iris$Species))
Ответ №3:
R — очень разнообразный язык программирования, и в конечном итоге будет много способов сделать то же самое. Некоторые функции ожидают более стандартной оценки, в то время как другие могут использовать NSE (нестандартную оценку).
Однако вы, похоже, спрашиваете о функциях, которые ожидают только один вектор как вменяемый, в отличие от функций, у которых есть data
аргумент, в котором вы используете variable
в отличие от data$variable
.
У меня есть несколько боковых панелей, прежде чем я дам несколько советов
Боковая панель 1 — Методы S3
Хотя это может быть не важно в отношении вопроса, функция kruskal.test
имеет два метода.
methods("kruskal.test")
#[1] kruskal.test.default* kruskal.test.formula*
#see '?methods' for accessing help and source code
Какой метод используется, зависит от класса первого аргумента в функции. В этом примере вы передаете выражение формулы, в котором data
аргумент необходим, тогда как метод по умолчанию требует только x
g
аргументов и (которые вы, вероятно, могли бы использовать в своих оригинальных конвейерах).
Итак, если вы привыкли делать что-то одним способом, обязательно проверьте, что в документации функции есть разные методы отправки, которые будут работать для вас.
Боковая панель 2 — Фреймы данных
Фреймы данных на самом деле представляют собой просто набор векторов. Разница между f(data$variable)
и f(x = variable, data = data)
заключается в том, что в первом пользователь явно указывает R, где найти вектор, в то время как во втором функция f
должна оцениваться x
в контексте data
. Я поднимаю этот вопрос из-за того, что я сказал в начале — есть много способов сделать то же самое. Так что, как правило, вам решать, каким должен быть ваш стандарт.
Если вы предпочитаете быть явным
vars <- c("data$age", "data$gender", "data$PCLR")
means <- sapply(vars, fmean, data$group, na.rm=TRUE)
krusk <- sapply(vars, kruskal.test, g = data$group)
или вы можете написать свои функции, в которых они должны оцениваться внутри определенного data.frame
объекта
vars <- c("age", "gender", "PCLR")
means <- sapply(vars, function(x, id, data) fmean(data[[x]], id = data[[id]], na.rm=T), id = "group", data = data)
krusk <- sapply(vars, function(x, id, data) kruskal.test(data[[x]], data[[id]]), id = "group", data = data)
Мой совет
Я рекомендую изучить следующие пакеты dplyr
, tidyr
, purrr
. Я уверен, что в этих пакетах есть несколько вещей, которые облегчат вашу жизнь.
Например, вы выразили необходимость вручную составить список перед выполнением sapply
. В dplyr
пакете вы можете обойти это, если есть условие для фильтрации.
data %>%
group_by(group) %>% #groups data
summarise_if(is.numeric, mean, na.rm = TRUE) #applys mean to every column that is a numeric vector
И аналогично, мы можем обобщить результаты kurskal.test
функции, если немного изменим данные.
data %>%
group_by(group) %>% #grouping to retain column in the next select statement
select_if(is.numeric) %>% # selecting all numeric columns
pivot_longer(cols = -group) %>% # all columns except "group" will be reshaped. Column names are stored in `name`, and values are stored in `values`
group_by(name) %>% #regroup on name variable (old numeric columns)
summarise(krusk = list(kruskal.test(value ~ as.factor(group)))) #perform test
Я упомянул только purrr
потому, что вы можете почти удалить и заменить все apply
функции стиля их map
вариантами. purrr
очень последователен во всех вариантах функций с множеством опций для управления типом вывода.
Я надеюсь, что это поможет и желаю вам удачи в ваших приключениях с кодированием.
Комментарии:
1. Привет, Джастин, спасибо за этот ответ! Я не видел другого способа выполнения kruskal.test, так что это определенно поможет в том, как я структурировал свою переменную vars на этот раз. На самом деле я уже часто использую dplyr, но я вижу, что мне нужно больше ознакомиться с тем, как использовать связанные функции. На самом деле у меня есть немного кода, использующего «summarise (across(starts_with («Pect»)», поскольку все переменные, которые мне нужно просмотреть, начинаются с этих слов (поэтому не обязательно только числовые переменные). Но я буду продолжать копаться в этой функции ‘select_if’!
2. Сделал это! Конечный результат для моего кода был: krusk <- data_clean %>% group_by(cutoff_26) %>% select(starts_with(«Pect»)) %>% pivot_longer(cols =-cutoff_26) %>% group_by(name) %>% summarise(krusk = list(kruskal.test(значение ~ как .factor(cutoff_26)))) Большое спасибо за вашу помощь!