Как объединить несколько функций R с помощью функций apply, включая ggplot2 - PullRequest
2 голосов
/ 27 мая 2020

У меня есть несколько отдельных фрагментов кода для запуска тестов нормальности в R, и я хотел бы иметь возможность комбинировать их, чтобы я мог проверять определенные c переменные, не копируя каждый раз код. Пока все отдельные фрагменты кода работают (на примере набора данных iris):

library(datasets)
library(tidyverse)
library(skimr)

data(iris)
iris$Species <- NULL

# descriptive statistics and normality tests
skim(iris$Sepal.Length)
round(stat.desc(iris$Sepal.Length, basic = FALSE, norm = TRUE), digits = 3)

# histogram with normality curve
hist_sepal_length <- ggplot(iris, aes(Sepal.Length)) + 
  geom_histogram(aes(y = ..density..), bins = 10, colour = "black", fill = "white") +
  labs(x = "Sepal.Length", y = "Density") + 
  stat_function(fun = dnorm, args = list(mean = mean(iris$Sepal.Length), sd = sd(iris$Sepal.Length)), colour = "black", size = 1)
hist_sepal_length

# qqplot
qqplot_sepal_length <- qplot(sample = iris$Sepal.Length)
qqplot_sepal_length

Я могу сделать первый шаг описательной статистики, используя sapply

round(sapply(iris, stat.desc, basic = FALSE, norm = TRUE), digits = 3)

Однако я не уверен, как использовать какие-либо функции apply с ggplot2. Я рассмотрел следующие вопросы:

Как использовать lapply с ggplot2 при индексировании переменных

с помощью функции apply с ggplot2 для создания гистограмм для более чем одна переменная в data.frame

Использование функций apply с ggplot для построения подмножества столбцов фрейма данных

Использование lapply для создания блочных диаграмм список переменных

Однако ни один из них полностью не покрывает то, что я хочу, так как мой ggplot также включает stat_function, которая ссылается на переменную. Также хотелось бы, чтобы результат был в виде отдельных графиков. Есть ли способ написать код ggplot, чтобы он проходил через все переменные сразу (длина чашелистика, ширина чашелистика, длина лепестка, ширина лепестка)? У меня есть переменные, для которых я хочу запустить тесты нормальности, уже сохраненные в отдельном фрейме данных, поэтому нет необходимости в подмножестве.

Наконец, есть ли способ объединить 3 шага вместе (тесты нормальности, гистограмма и график qq) в одну функцию?

1 Ответ

2 голосов
/ 27 мая 2020

Цель состоит в том, чтобы попытаться заменить всякий раз, когда у вас есть Sepal.Length для общей c переменной. После этого вы можете создать функцию и вызвать ее для каждой переменной. Затем просто обобщить al oop, который вернет все результаты сразу.

library(datasets)
library(tidyverse)
library(skimr)
library(pastecs)

data(iris)
#-- Function
testVarNormality <- function(var, data) {
    # descriptive statistics and normality tests
    skim_res <- skim(data[,var])
    desc_stats <- round(stat.desc(data[,var], basic = FALSE, norm = TRUE), digits = 3)

    # histogram with normality curve
    hist <- ggplot(data, aes_string(var)) + 
        geom_histogram(aes(y = ..density..), bins = 10, colour = "black", fill = "white") +
        labs(x = var, y = "Density") + 
        stat_function(fun = dnorm, args = list(mean = mean(data[,var]), sd = sd(data[,var])), colour = "black", size = 1)

    # qqplot
    qqplot <- qplot(sample = data[,var])

    list(skim_res = skim_res, desc_stats = desc_stats, histogram = hist, qqplot = qqplot)
}
#-- 1 function call
sepal_length_res <- testVarNormality("Sepal.Length", iris)
sepal_length_res$histogram
sepal_length_res$qqplot

#-- Calling for all columns (except species)
all_res <- lapply(colnames(iris)[1:4], testVarNormality, iris)
names(all_res) <- colnames(iris)[1:4]
#-- Get a result example
all_res$Sepal.Width$histogram

----

Как это сделать по видам:

irisBySpecies <- split(iris, iris$Species)
#-- Nested list

    res_byGroup <- lapply(
        irisBySpecies,
        function(species_data) {
            res4species <- lapply(colnames(species_data)[1:4], testVarNormality, species_data)
            names(res4species) <- colnames(iris)[1:4]
            return(res4species)
        }
    )
    names(res_byGroup) <- names(irisBySpecies)

Обратите внимание, что для этого мне пришлось сделать анонимную функцию. Вероятно, есть более элегантные способы создания кода для исходной функции, которые упростили бы применение для каждой группы, но этот способ вполне универсален.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...