Buscar..


Observaciones

Una función en la familia *apply es una abstracción de un bucle for . En comparación con el for bucles *apply las funciones tienen las siguientes ventajas:

  1. Requieren menos código para escribir.
  2. No tiene un contador de iteración.
  3. No utiliza variables temporales para almacenar resultados intermedios.

Sin embargo for bucles son más generales y nos puede dar más control que permite lograr cálculos complejos que no siempre son triviales para hacer uso de *apply funciones.

La relación entre los bucles for y las funciones *apply se explica en la documentación for bucles for .

Miembros de la familia *apply

La familia de funciones *apply contiene varias variantes del mismo principio que difieren principalmente en función del tipo de resultado que devuelven.

función Entrada Salida
apply matrix , data.frame o array Vector o matriz (dependiendo de la longitud de cada elemento devuelto)
sapply vector o list Vector o matriz (dependiendo de la longitud de cada elemento devuelto)
lapply vector o list list
vapply vector o `lista Vector o matriz (dependiendo de la longitud de cada elemento devuelto) de la clase designada por el usuario
mapply Múltiples vectores, lists o una combinación. list

Consulte "Ejemplos" para ver cómo se utiliza cada una de estas funciones.

Utilizar funciones anónimas con aplicar.

apply se utiliza para evaluar una función (tal vez anónima) sobre los márgenes de una matriz o matriz.

Usemos el conjunto de datos del iris para ilustrar esta idea. El conjunto de datos del iris tiene medidas de 150 flores de 3 especies. Veamos cómo está estructurado este conjunto de datos:

> head(iris)

  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1         5.1          3.5          1.4         0.2  setosa
2         4.9          3.0          1.4         0.2  setosa
3         4.7          3.2          1.3         0.2  setosa
4         4.6          3.1          1.5         0.2  setosa
5         5.0          3.6          1.4         0.2  setosa
6         5.4          3.9          1.7         0.4  setosa

Ahora, imagina que quieres saber la media de cada una de estas variables. Una forma de resolver esto podría ser usar un bucle for , pero los programadores de R a menudo preferirán usar apply (por los motivos, ver Comentarios):

> apply(iris[1:4], 2, mean)

Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
    5.843333     3.057333     3.758000     1.199333
  • En el primer parámetro, subcompusimos el iris para incluir solo las primeras 4 columnas, porque la mean solo funciona en datos numéricos.
  • El segundo valor de parámetro de 2 indica que queremos trabajar solo en las columnas (el segundo subíndice de la matriz r × c); 1 daría a los medios de fila.

De la misma manera podemos calcular valores más significativos:

# standard deviation
apply(iris[1:4], 2, sd)
# variance
apply(iris[1:4], 2, var)

Advertencia : R tiene algunas funciones incorporadas que son mejores para calcular sumas y medios de columnas y filas: colMeans y rowMeans .

Ahora, hagamos una tarea diferente y más significativa: calculemos la media solo para aquellos valores que son mayores que 0.5 . Para eso, crearemos nuestra propia función mean .

> our.mean.function <- function(x) { mean(x[x > 0.5]) }
> apply(iris[1:4], 2, our.mean.function)

Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
    5.843333     3.057333     3.758000     1.665347

(Note la diferencia en la media de Petal.Width )

Pero, ¿qué pasa si no queremos usar esta función en el resto de nuestro código? Luego, podemos usar una función anónima y escribir nuestro código así:

apply(iris[1:4], 2, function(x) { mean(x[x > 0.5]) })

Entonces, como hemos visto, podemos usar apply para ejecutar la misma operación en columnas o filas de un conjunto de datos usando solo una línea.

Advertencia : dado que la apply devuelve tipos de salida muy diferentes dependiendo de la longitud de los resultados de la función especificada, puede que no sea la mejor opción en los casos en que no esté trabajando de forma interactiva. Algunas de las otras *apply funciones de la familia de *apply son un poco más predecibles (ver Comentarios).

Carga masiva de archivos

para una gran cantidad de archivos que pueden necesitar ser operados en un proceso similar y con nombres de archivos bien estructurados.

En primer lugar, se debe crear un vector de los nombres de archivo a los que se va a acceder, hay varias opciones para esto:

  • Creando el vector manualmente con paste0()

     files <- paste0("file_", 1:100, ".rds")
    
  • El uso de list.files() con un término de búsqueda regex para el tipo de archivo, requiere conocimiento de expresiones regulares ( regex ) si hay otros archivos del mismo tipo en el directorio.

     files <- list.files("./", pattern = "\\.rds$", full.names = TRUE)
    

donde X es un vector de parte del formato de denominación de archivos utilizado.

lapply dará salida a cada respuesta como elemento de una lista.

readRDS es específico de los archivos .rds y cambiará según la aplicación del proceso.

my_file_list <- lapply(files, readRDS)

Esto no es necesariamente más rápido que un bucle for de las pruebas, pero permite que todos los archivos sean un elemento de una lista sin asignarlos explícitamente.

Finalmente, a menudo necesitamos cargar varios paquetes a la vez. Este truco puede hacerlo fácilmente aplicando library() a todas las bibliotecas que deseamos importar:

lapply(c("jsonlite","stringr","igraph"),library,character.only=TRUE)

Combinando múltiples `data.frames` (` lapply`, `mapply`)

En este ejercicio, generaremos cuatro modelos de regresión lineal bootstrap y combinaremos los resúmenes de estos modelos en un solo marco de datos.

library(broom)

#* Create the bootstrap data sets
BootData <- lapply(1:4,
                   function(i) mtcars[sample(1:nrow(mtcars),
                                             size = nrow(mtcars),
                                             replace = TRUE), ])

#* Fit the models
Models <- lapply(BootData,
                 function(BD) lm(mpg ~ qsec + wt + factor(am),
                                 data = BD))

#* Tidy the output into a data.frame
Tidied <- lapply(Models,
                 tidy)

#* Give each element in the Tidied list a name
Tidied <- setNames(Tidied, paste0("Boot", seq_along(Tidied)))

En este punto, podemos adoptar dos enfoques para insertar los nombres en el data.frame.

#* Insert the element name into the summary with `lapply`
#* Requires passing the names attribute to `lapply` and referencing `Tidied` within
#* the applied function.
Described_lapply <- 
 lapply(names(Tidied),
        function(nm) cbind(nm, Tidied[[nm]]))

Combined_lapply <- do.call("rbind", Described_lapply)

#* Insert the element name into the summary with `mapply`
#* Allows us to pass the names and the elements as separate arguments.
Described_mapply <- 
 mapply(
  function(nm, dframe) cbind(nm, dframe),
  names(Tidied),
  Tidied,
  SIMPLIFY = FALSE)

Combined_mapply <- do.call("rbind", Described_mapply)

Si es un fanático de las magrittr estilo magrittr , puede realizar la tarea completa en una sola cadena (aunque puede que no sea prudente hacerlo si necesita alguno de los objetos intermedios, como los objetos del modelo en sí):

library(magrittr)
library(broom)
Combined <- lapply(1:4,
                   function(i) mtcars[sample(1:nrow(mtcars),
                                             size = nrow(mtcars),
                                             replace = TRUE), ]) %>%
 lapply(function(BD) lm( mpg ~ qsec + wt + factor(am), data = BD)) %>%
 lapply(tidy) %>%
 setNames(paste0("Boot", seq_along(.))) %>%
 mapply(function(nm, dframe) cbind(nm, dframe),
        nm = names(.),
        dframe = .,
        SIMPLIFY = FALSE) %>%
 do.call("rbind", .)

Usando funciones incorporadas

Funcionales incorporados: lapply (), sapply () y mapply ()

R viene con funciones integradas, de las cuales quizás las más conocidas son la familia de funciones de aplicación. Aquí hay una descripción de algunas de las funciones de aplicación más comunes:

  • lapply() = toma una lista como argumento y aplica la función especificada a la lista.
  • sapply() = igual que lapply() pero intenta simplificar la salida a un vector o una matriz.
    • vapply() = una variante de sapply() en la que se debe especificar el tipo de objeto de salida.
  • mapply() = como lapply() pero puede pasar múltiples vectores como entrada a la función especificada. Se puede simplificar como sapply() .
    • Map() es un alias para mapply() con SIMPLIFY = FALSE .

lapturar ()

lapply() se puede utilizar con dos iteraciones diferentes:

  • lapply(variable, FUN)
  • lapply(seq_along(variable), FUN)
# Two ways of finding the mean of x
set.seed(1)
df <- data.frame(x = rnorm(25), y = rnorm(25))
lapply(df, mean)
lapply(seq_along(df), function(x) mean(df[[x]))

suministro ()

sapply() intentará resolver su salida a un vector o una matriz.

# Two examples to show the different outputs of sapply()
sapply(letters, print)  ## produces a vector
x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,FALSE,TRUE))
sapply(x, quantile)  ## produces a matrix

mapply ()

mapply() funciona de manera muy similar a lapply() excepto que puede tomar múltiples vectores como entrada (de ahí la m para multivariable).

mapply(sum, 1:5, 10:6, 3) # 3 will be "recycled" by mapply

Usando funciones definidas por el usuario

Funcionales definidos por el usuario

Los usuarios pueden crear sus propios funcionales en diversos grados de complejidad. Los siguientes ejemplos son de Functionals by Hadley Wickham:

randomise <- function(f) f(runif(1e3))
        
lapply2 <- function(x, f, ...) {
    out <- vector("list", length(x))
    for (i in seq_along(x)) {
        out[[i]] <- f(x[[i]], ...)
    }
    out
}

En el primer caso, randomise acepta un solo argumento f , y lo llama en una muestra de variables aleatorias uniformes. Para demostrar la equivalencia, llamamos set.seed continuación:

set.seed(123)
randomise(mean)
#[1] 0.4972778
    
set.seed(123)
mean(runif(1e3))
#[1] 0.4972778


set.seed(123)
randomise(max)
#[1] 0.9994045

set.seed(123)
max(runif(1e3))
#[1] 0.9994045

El segundo ejemplo es una reimplementación de base::lapply , que utiliza funciones para aplicar una operación ( f ) a cada elemento de una lista ( x ). El parámetro ... permite al usuario pasar argumentos adicionales a f , como la opción na.rm en la función mean :

lapply(list(c(1, 3, 5), c(2, NA, 6)), mean)
# [[1]]
# [1] 3
# 
# [[2]]
# [1] NA

lapply2(list(c(1, 3, 5), c(2, NA, 6)), mean)
# [[1]]
# [1] 3
# 
# [[2]]
# [1] NA


lapply(list(c(1, 3, 5), c(2, NA, 6)), mean, na.rm = TRUE)
# [[1]]
# [1] 3
# 
# [[2]]
# [1] 4

lapply2(list(c(1, 3, 5), c(2, NA, 6)), mean, na.rm = TRUE)
# [[1]]
# [1] 3
# 
# [[2]]
# [1] 4


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow