#r #function
#r #функция
Вопрос:
Прежде всего, это мой первый вопрос по stackoverflow. Я попытался написать свой вопрос (ниже) с некоторым здравым смыслом (описательное название для других, чтобы другие могли легко искать и находить его, воспроизводимый код, …), но если есть какие-либо рекомендации или исправления для будущих вопросов, которые я бы попросил, чтобы всем вам было удобнее отвечать, пожалуйста, укажитеэто мне в ответах.
Вопрос :
Мне удалось написать некоторый код, дающий мне именно то, что я хочу. Это не должно быть причиной для того, чтобы задавать вопрос на этой доске, однако мне приходится копировать и вставлять один и тот же фрагмент много десятков раз с небольшими и очень предсказуемыми изменениями.
Поэтому я решил написать свою собственную функцию, чтобы сэкономить время. Эта функция не удалась, и мне кажется, что это просто расширение предыдущих методов построения собственной функции в R-скрипте.
Я разрезал исходную функцию donw на более мелкие части, чтобы понять, что пошло не так (и уменьшить количество шагов и вводимых аргументов), и обнаружил одну специфическую часть исходного скрипта, которая не удалась, и я не могу обойти.
По сути, мои вопросы сводятся к :
- Почему аргумент «Переменная» не изменяется аргументом, который я указал, когда я запускаю функцию?
- Как я должен изменить свой скрипт, чтобы исправить это?
Код :
(Мне не разрешено передавать какую-либо часть моей базы данных, поэтому я использую набор данных gapminder, который содержит переменные с аналогичными характеристиками).
#Package
library(tidyverse)
library(questionr)
library(haven)
library(knitr)
library(tidyr)
library(qwraps2)
library(matrixStats)
library(reldist)
library(gapminder)
#Reproductible data
db <- gapminder
#Function
Liste <- function(Variable)
{
Liste <-
list(list("Minimum" = ~eval(parse(text = paste("min(",Variable," na.rm = TRUE"))),
"Moyenne" = ~mean(Variable, na.rm = TRUE),
"Mediane" = ~median(Variable, na.rm = TRUE),
"Maximum" = ~max(Variable, na.rm = TRUE),
"Caracteristiques position" = ~ifelse(mean(Variable, na.rm = TRUE)>median(Variable, na.rm = TRUE),"Moyenne > Mediane",ifelse(mean(Variable, na.rm = TRUE)<median(Variable, na.rm = TRUE),"Mediane > Moyenne","Moyenne = Mediane")),
"Valeur manquante" = ~sum(is.na(Variable)),
"D1" = ~quantile(Variable, 0.1, na.rm = TRUE),
"Q25" = ~quantile(Variable, 0.25, na.rm = TRUE),
"Q75" = ~quantile(Variable, 0.75, na.rm = TRUE),
"D9" = ~quantile(Variable, 0.9, na.rm = TRUE)
))
}
Liste_Test <- Liste(Variable = lifeExp)
Подведение итогов проблемы
Если вы откроете объект «Liste_Test» вместо замены «Переменной» на «lifeExp», ничего не изменится. Это мешает правильной работе остальной части функции.
Вы можете заметить, что первый элемент созданного списка отличается:
"Minimum" = ~eval(parse(text = paste("min(",Variable," na.rm = TRUE")))
Это первая попытка использовать so close questions на плате StackOverflow. Результат точно такой же.
Я также нашел некоторый ответ, рекомендующий использовать функцию «do.call». Однако я не могу понять, как это должно работать и, следовательно, какую модификацию я должен сделать. Чтобы дать вам представление об ожидаемом результате, вы можете добавить этот фрагмент (не в виде функции) в предыдущий сценарий.
Я надеюсь, что я предоставил полное, хотя и не слишком длинное объяснение моей проблемы и вопросов.
Комментарии:
1. Это сильный первый вопрос, но я бы хотел, чтобы ваш пример был более минимальным — я не думаю, что вы используете почти любой пакет, для которого у вас есть
library()
вызовы. У меня нетquestionr
,reldist
, илиqwraps2
установлен. Но я не думаю, что вы используете какие-либо пакеты, кромеgapminder
как для выборки данных иpurrr
(загруженныхtidyverse
) для синтаксиса~
функции. Может быть, вы могли бы удалить остальныеlibrary
вызовы?2. Я бы также посоветовал вам свести проблему к минимуму —
list("Minimum" = ~eval(parse(text = paste("min(",Variable," na.rm = TRUE"))),"Moyenne" = ~mean(Variable, na.rm = TRUE)
достаточно? Или вам действительно нужно еще 9 статистических данных? Но это всего лишь отзыв о том, как вы задали вопрос, что в целом неплохо для первого вопроса.3. Спасибо за отзыв о том, как я написал вопрос. Я подумал о количестве пакетов, которые я вставил в код, но именно в первом проекте большинство (возможно, не все) имело смысл. Я забыл обновить список, когда удалил отклонение этого вопроса с помощью взвешенных функций. Что касается длины кода, я уменьшу его в следующий раз, поскольку переход от списка из двух статистических данных к большему списку — это просто расширение того, что можно сделать, если найдено решение.
Ответ №1:
Когда вы передаете имена столбцов в качестве аргумента функции, вам нужно кодировать вещи иначе, чем вы обычно делаете. (Читайте о нестандартной оценке)
Вы передаете Liste(Variable = lifeExp)
, но R не знает, что lifeExp
это такое (введите это в консоли и посмотрите, что вы получите).
Чтобы все было просто, передайте значения вместо имени столбца здесь.
Liste <- function(Variable)
{
list("Minimum" = min(Variable, na.rm = TRUE),
"Moyenne" = mean(Variable, na.rm = TRUE),
"Mediane" = median(Variable, na.rm = TRUE),
"Maximum" = max(Variable, na.rm = TRUE),
"Caracteristiques position" = ifelse(mean(Variable, na.rm = TRUE) >
median(Variable, na.rm = TRUE),"Moyenne > Mediane",
ifelse(mean(Variable, na.rm = TRUE) < median(Variable, na.rm = TRUE),
"Mediane > Moyenne","Moyenne = Mediane")),
"Valeur manquante" = sum(is.na(Variable)),
"D1" = quantile(Variable, 0.1, na.rm = TRUE),
"Q25" = quantile(Variable, 0.25, na.rm = TRUE),
"Q75" = quantile(Variable, 0.75, na.rm = TRUE),
"D9" = quantile(Variable, 0.9, na.rm = TRUE))
}
и затем вы можете вызвать эту функцию как :
Liste(db$lifeExp)
Комментарии:
1. Спасибо за этот ответ. Это ответ, наиболее близкий к исходному способу написания моего кода, поэтому я основывался на нем (я опубликую, как я использовал ответы для получения результата, который я искал). Глядя на то, как вы это переписали, я думаю, что я откажусь от использования
summary_table
функции изqwarps2
пакета. Кстати, я не вставлял весь исходный пример сценария. Это объясняет, почему я не назвал data.frame источника в функции, а только переменную в ней.
Ответ №2:
Используя rlang
‘s ensym
, мы можем заключить имя в кавычки, т.е. Вы можете передать имя так, как вы делали без кавычек, и правильно обработать его. более простой альтернативой было бы использовать deparse(substitute(Variable))
. проблема, с которой вы столкнулись в своем коде, заключается в том, что вы передали lifeExp
вместо "lifeExp"
и если вы передали имя переменной правильно, как бы вы справились с этим на другой стороне, не имея доступа к data.frame
?
library(tidyverse)
library(rlang)
sommaire <- function(df, Variable){
Variable <- ensym(Variable)
df %>%
summarise(Minimum = min(!!Variable, na.rm=T), Moyenne = mean(!!Variable, na.rm=T), Mediane= median(!!Variable, na.rm=T),
Maximum = max(!!Variable, na.rm=T), `Caracteristiques position` = sprintf("Moyenne %s Mediane", case_when(Moyenne > Mediane ~ ">", Moyenne==Mediane ~ "=", T ~ "<")),
`Valeur manquante` = sum(is.na(!!Variable)), data=list(set_names(quantile(!!Variable, c(.1, .25, .75, .9), na.rm=T), c("D1", "Q25", "Q75", "D9")))) %>%
unnest_wider(data)
}
sommaire(db, lifeExp)
# A tibble: 1 x 10
Minimum Moyenne Mediane Maximum `Caracteristiques position` `Valeur manquante` D1 Q25 Q75 D9
<dbl> <dbl> <dbl> <dbl> <chr> <int> <dbl> <dbl> <dbl> <dbl>
1 23.6 59.5 60.7 82.6 Moyenne < Mediane 0 41.5 48.2 70.8 75.1
Вы можете применить это ко всем числовым переменным, используя purrr::map
:
map(set_names(colnames(db)[sapply(db, is.numeric)]), sommaire, df=db) %>% bind_rows(.id="Variable")
# A tibble: 4 x 11
Variable Minimum Moyenne Mediane Maximum `Caracteristiques position` `Valeur manquante` D1 Q25 Q75 D9
<chr> <dbl> <dbl> <dbl> <dbl> <chr> <int> <dbl> <dbl> <dbl> <dbl>
1 year 1952 1980. 1980. 2007 Moyenne = Mediane 0 1957 1966. 1993. 2002
2 lifeExp 23.6 59.5 60.7 82.6 Moyenne < Mediane 0 41.5 48.2 70.8 75.1
3 pop 60011 29601212. 7023596. 1318683096 Moyenne > Mediane 0 946367. 2793664 19585222. 54801370.
4 gdpPercap 241. 7215. 3532. 113523. Moyenne > Mediane 0 688. 1202. 9325. 19449.
Комментарии:
1. Спасибо за этот ответ. Это близко к тому, что я искал, особенно второй сценарий для того, что я имею в виду в качестве первого шага (имея первый обзор набора переменных в моей базе данных). Причина, по которой я не называю data.frame источника переменной, заключается в том, что я изначально использую функцию
summary_table
из пакетаqwarps2
. Я просто замечаю, что я не вставил весь код, отсюда отсутствие примера того, что я хочу иметь в конце, и правильной иллюстрации того, почему я хотел назвать только переменную, не называя data.frame происхождения.
Ответ №3:
Спасибо всем за ответы.
Я также приношу извинения за то, что не вставил весь пример сценария (моя ошибка, плохая перепроверка перед нажатием кнопки отправки). Часть причины, по которой я решил написать функцию таким образом, исходит от меня, используя summary_table
из qwarps2
пакета. Предоставленный вами ответ позволяет мне отказаться от использования функции и пакета, которые делают все это более сложным.
Вот как я использовал ваш ответ для решения своей проблемы.
СТРАТЕГИИ
Я отформатировал свою первоначальную попытку так, чтобы результаты отображались по вертикали, а не по горизонтали, потому что я хочу использовать их в RMarkdown для отчетов и рабочих документов, и этот формат более удобен для меня.
Поэтому я действовал в два этапа :
- Изменение моей исходной функции, чтобы сделать ее функциональной ;
- Создайте функцию, чтобы создать ее в правильном формате (возможно, с чрезмерной конвульсией).
Исправлена исходная функция
Liste <- function(Variable)
{
list("Minimum" = min(Variable, na.rm = TRUE),
"Moyenne" = mean(Variable, na.rm = TRUE),
"Mediane" = median(Variable, na.rm = TRUE),
"Maximum" = max(Variable, na.rm = TRUE),
"Position" = ifelse(mean(Variable, na.rm = TRUE) >
median(Variable, na.rm = TRUE),"Moyenne > Mediane",
ifelse(mean(Variable, na.rm = TRUE) < median(Variable, na.rm = TRUE),
"Mediane > Moyenne","Moyenne = Mediane")),
"Presente" = sum(!is.na(Variable))
"Manquante" = sum(is.na(Variable)),
"D1" = quantile(Variable, 0.1, na.rm = TRUE),
"Q25" = quantile(Variable, 0.25, na.rm = TRUE),
"Q75" = quantile(Variable, 0.75, na.rm = TRUE),
"D9" = quantile(Variable, 0.9, na.rm = TRUE))
}
Дополнительная функция (вертикальный формат)
Sommaire <- function(Variable)
{
Tableau <- as.data.frame(Liste(Variable))
Tableau <- data.frame(t(Tableau[-1]))
return(Tableau)
}
Еще раз спасибо всем за помощь