Chapter 9 Escribir funciones en R

9.1 Un refresco rápido

Vamos a recordar rápidamente cómo se hace una función

9.1.1 Estructura básica de una función

Una función en R se compone básicamente de 3 partes, como veremos a continuación en una función que hemos llamado mi funcion:

  • Usamos la función function() para crear una nueva función.
  • Los argumentos de esa función están definidos en el interior de ese paréntesis (arg1, arg2, etc).
  • El cuerpo de la función aparece después, entre llaves {}, y es el código que se ejecuta cada vez que se llama a la función.
mi_funcion <- function(arg1, arg2) {
  cuerpo
}

9.1.1.1 Un ejemplo sencillo de función

Vamos a generar una función que vamos a llamar sumar.

sumar <- function(x, y = 1) {
  x + y
}

Como vemos, la función sumar() tiene dos argumentos: x e y = 1. Su cuerpo está compuesto por la suma de x + y.

Cuando introduzcamos un valor en la función, por ejemplo, sumar(5), lo que hemos hecho es decirle a la función que x = 5. Como de modo predeterminado y = 1, el resultado será 6 (5 + 1).

Es interesante destacar que los valores asignados dentro del paréntesis, por ejemplo y = 1 en nuestra función sumar(), indican los valores predeterminados que debe adquirir esos atributos cuando en la función no se especifica ningún valor.

# El resultado de sumar x = 5 e y = 1 (de modo predeterminado)
sumar(5)
## [1] 6
# Cuando queremos dar otro valor a la variable y hay que indicárselo, en este caso y = 3
sumar(5, 3)
## [1] 8

9.1.2 Estructura de una función

Vamos a desgranar la función sumar(). Cualquier función está compuesta por tres componentes:

  • Argumentos formales. Podemos verlos con formals().
  • Cuerpo. Podemos verlo con body()
  • Entorno. Podemos verlo con environment()
# Nos indica los elementos que hay, en este caso "x" e "y", indicando cuál es el valor predeterminado
formals(sumar)
## $x
## 
## 
## $y
## [1] 1
# Nos indica la función a ejecutar situada entre las llaves {}
body(sumar)
## {
##     x + y
## }
# Vemos el entorno en el que se ejecutará la función, suele ser "R_GlobalEnv"
environment(sumar)
## <environment: R_GlobalEnv>

9.1.2.1 Un ejemplo algo más complejo

Vamos a ver un ejemplo algo más complejo en el que la función devolverá siempre el valor absoluto del valor “x” introducido. Para ello usaremos la función if() con else.

valor_absoluto <- function(x) {
  if(x < 0) {
    -x
  } else {
    x
  }
}

9.1.3 Función return()

La última expresión evaluada en una función es el valor devuelto (return value).

Si queremos que la función nos devuelva en algún momento el valor intermedio, tendremos que usar la función return(). Veamos la siguiente función.

# Función con "return()"
fun.ret <- function(x) {
  if (TRUE) {
    return(x + 1)
  }
  x
}

# Función sin "return()"
fun.no.ret <- function(x) {
  if (TRUE) {
    x + 1
  }
  x
}

# Vamos a hacer que "x = 2" en ambas funciones
fun.ret(2)
## [1] 3
fun.no.ret(2)
## [1] 2

Vemos claramente cómo la función return(x + 1) devuelve el valor porque fuerza la función a mostrarlo, mientras que en la segunda, como no es obligatorio, y no sabe interpretar si es TRUE o FALSE devuelve el valor de x sin más.

9.1.4 Funciones como objetos

En R, las funciones funcionan como cualquier otro objeto con <-. Si no llevan asociadas ningún nombre, se las conoce como funciones anónimas.

# Le decimos que la función "mean()" se llame ahora media2
media2 <- mean

# Ejecutamos "media2"
media2(1:10)
## [1] 5.5
# Creamos una función sin ningún nombre y sin asignarla a ningún objeto
function(x) {x + 1}
## function(x) {x + 1}
# Ejecutamos la función anterior poniendo el valor de 5, tal y como se ve
(function(x) {x + 1}) (5)
## [1] 6

9.1.5 Cómo escribir los argumentos

Los argumentos los podemos escribir de dos formas:

  • Sin poner el nombre del argumento e = (5)
  • Poniendo el nombre del argumento e = (x = 5)

Es recomendable que se escriban los nombres, especialmente cuando son argumentos opcionales que presentan un valor predefinido.

Por lo tanto, se recomienda escribir así los argumentos:

  • Primero los argumentos obligatorios, sin escribir el nombre del mismo, solo su valor.
  • Segundo los argumentos opcionales, escribiendo el nombre del mismo y su valor.
  • Uso de un espacio después de las comas, como sie estuviéramos escribiendo en nuestro idioma.

Si un argumento no está escrito en la función, la función buscará en el ambiente exterior a la función.

9.1.6 Environments / Scoping

Cada vez que se crea una función, al ejecutarla se crea un nuevo ambiente (environment) donde la función hace su trabajo.

Este nuevo ambiente está compuesto por los valores de los argumentos.

Los objetos de dentro de la función se buscan siempre primero dentro de este ambiente de la función, y si no lo encuentra, lo mira en un nivel superior, es decir, el ambiente en el que la función fue creada.

# Ejemplo 1. ¿Qué da el resultado de f(10)?
y <- 10
f <- function(x) {
  y <- 5
  x + y
}

El resultado de f(10) es 15. Como la y de dentro de la función vale 5, es el valor que la función porque se encuentra dentro de su ambiente, ignorando el valor de y = 10 que está fuera de la función. Si el valor de y no estuviera dentro la función, sí que lo hubiera tenido en cuenta porque dentro de la función no está definido y lo busca en un nivel superior: el ambiente en el que la función se definió.

# Ejemplo 2. ¿Qué sale si queremos ver el valor de y?
f <- function(x) {
  y <- 5
  x + y
}
f(5)
## [1] 10

El resultado es un error. Y esto es así porque los objetos generados dentro de una función solo funcionan dentro de esa función, y no en el ambiente en el que esa función fue generada.

9.1.7 Estructura de datos

Existen dos tipos de vectores en R:

  • Vectores atómicos (atomic vectors). Estos vectores son homogéneos, es decir, solo contienen un tipo de datos (se puede comprobar con la función typeof() y length(). Entre otros, estos vectores tienen los siguientes tipos de datos:
    • Logical
    • Integer
    • Double
    • Character
    • Complex
    • Raw
  • Listas. Pueden ser heterogéneas y contener otras listas.

9.1.7.1 Missing values

  • NULL. Se refiere a la ausencia de un vector.
  • NA. Se refiere a la ausencia de un valor dentro de un vector.
typeof(NULL)
## [1] "NULL"
length(NULL)
## [1] 0
typeof(NA)
## [1] "logical"
length(NA)
## [1] 1
x <- c(1:4, NA, NA, 7:10)
is.na(x)
##  [1] FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE

Los NA son contagiosos, porque todo lo que se compare con ellos devuelve un valor lógico.

9.1.7.2 Subsetting listas

Las listas son muy útiles porque pueden contener diferentes elementos heterogéneos. Muchos análisis estadísticos devuelven como resultado listas, como lm().

Podemos hacer subsets con [], [[]] o $:

  • []. Extrae una sublista.
  • [[]]. Extrae elementos de una sublista. Elimina por tanto un nivel de la jerarquía.
# Veamos una lista (A) con 4 sublistas dentro (a, b, c, d)
a <- list(
  a = 1:3, # vector numerico
  b = "a string", # una cadena de texto
  c = pi, # un número fijo
  d = list(-1, -5) # otra lista
)

# Subsetting 1. Vemos la estructura de la sublista d
str(a[4])
## List of 1
##  $ d:List of 2
##   ..$ : num -1
##   ..$ : num -5
str(a[[4]])
## List of 2
##  $ : num -1
##  $ : num -5

There are a few ways to subset a list. Throughout the course we’ll mostly use double bracket ([[]]) subsetting by index and by name.

That is, my_list[[1]] extracts the first element of the list my_list, and my_list[[“name”]] extracts the element in my_list that is called name. If the list is nested you can travel down the hierarchy by recursive subsetting. For example, mylist[[1]][[“name”]] is the element called name inside the first element of my_list.

A data frame is just a special kind of list, so you can use double bracket subsetting on data frames too. my_df[[1]] will extract the first column of a data frame and my_df[[“name”]] will extract the column named name from the data frame.

I’ve set up a list called tricky_list in your workspace. Use the function typeof() combined with double bracket subsetting to answer the following questions.

tricky_list <- structure(list(nums = c(0.429916550049076, 1.41361327183529, 
0.0585300675475498, 0.778238434550828, -0.18539773597979, 1.26639268091677, 
0.510122471874456, 0.613626708678488, -0.624355557411703, -2.27105997117704
), y = c(FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, 
TRUE, TRUE), x = list("hello!", "hi!", "goodbye!", "bye!"), model = structure(list(
    coefficients = structure(c(37.285126167342, -5.34447157272267
    ), .Names = c("(Intercept)", "wt")), residuals = structure(c(-2.28261064680868, 
    -0.919770395764334, -2.08595211862542, 1.29734993896137, 
    -0.200143957176023, -0.693254525721567, -3.90536265272207, 
    4.16373814964331, 2.3499592867344, 0.299856042823977, -1.10014395717602, 
    0.866873133639263, -0.0502472010864456, -1.88302362245031, 
    1.17334958945202, 2.10328764310577, 5.98107438886067, 6.87271129264786, 
    1.7461954226051, 6.42197916860408, -2.61100374058063, -2.97258623135821, 
    -3.72686631503964, -3.46235532808695, 2.46436702977666, 0.356426325876354, 
    0.152042998284502, 1.20105932218738, -4.54315128181114, -2.78093991090021, 
    -3.20536265272207, -1.02749519517299), .Names = c("Mazda RX4", 
    "Mazda RX4 Wag", "Datsun 710", "Hornet 4 Drive", "Hornet Sportabout", 
    "Valiant", "Duster 360", "Merc 240D", "Merc 230", "Merc 280", 
    "Merc 280C", "Merc 450SE", "Merc 450SL", "Merc 450SLC", "Cadillac Fleetwood", 
    "Lincoln Continental", "Chrysler Imperial", "Fiat 128", "Honda Civic", 
    "Toyota Corolla", "Toyota Corona", "Dodge Challenger", "AMC Javelin", 
    "Camaro Z28", "Pontiac Firebird", "Fiat X1-9", "Porsche 914-2", 
    "Lotus Europa", "Ford Pantera L", "Ferrari Dino", "Maserati Bora", 
    "Volvo 142E")), effects = structure(c(-113.649737406208, 
    -29.1157216973349, -1.66133394425872, 1.63139433490818, 0.111130494475281, 
    -0.384004069118752, -3.60724416888595, 4.50031253940073, 
    2.6905816665888, 0.611130494475281, -0.788869505524717, 1.11439174126316, 
    0.231679322361766, -1.60615708662333, 1.30145248921506, 2.21378178594695, 
    6.09956331214339, 7.30947343730549, 2.24215942243103, 6.89567922289664, 
    -2.20105953031548, -2.66940775990086, -3.41508586462621, 
    -3.19156077740543, 2.73465558169606, 0.820006404926464, 0.594877128087599, 
    1.70734569676061, -4.20455289700524, -2.40186162512452, -2.90724416888595, 
    -0.649428906921545), .Names = c("(Intercept)", "wt", "", 
    "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 
    "", "", "", "", "", "", "", "", "", "", "", "", "", "")), 
    rank = 2L, fitted.values = structure(c(23.2826106468087, 
    21.9197703957643, 24.8859521186254, 20.1026500610386, 18.900143957176, 
    18.7932545257216, 18.2053626527221, 20.2362618503567, 20.4500407132656, 
    18.900143957176, 18.900143957176, 15.5331268663607, 17.3502472010864, 
    17.0830236224503, 9.22665041054798, 8.29671235689423, 8.71892561113933, 
    25.5272887073521, 28.6538045773949, 27.4780208313959, 24.1110037405806, 
    18.4725862313582, 18.9268663150396, 16.762355328087, 16.7356329702233, 
    26.9435736741236, 25.8479570017155, 29.1989406778126, 20.3431512818111, 
    22.4809399109002, 18.2053626527221, 22.427495195173), .Names = c("Mazda RX4", 
    "Mazda RX4 Wag", "Datsun 710", "Hornet 4 Drive", "Hornet Sportabout", 
    "Valiant", "Duster 360", "Merc 240D", "Merc 230", "Merc 280", 
    "Merc 280C", "Merc 450SE", "Merc 450SL", "Merc 450SLC", "Cadillac Fleetwood", 
    "Lincoln Continental", "Chrysler Imperial", "Fiat 128", "Honda Civic", 
    "Toyota Corolla", "Toyota Corona", "Dodge Challenger", "AMC Javelin", 
    "Camaro Z28", "Pontiac Firebird", "Fiat X1-9", "Porsche 914-2", 
    "Lotus Europa", "Ford Pantera L", "Ferrari Dino", "Maserati Bora", 
    "Volvo 142E")), assign = 0:1, qr = structure(list(qr = structure(c(-5.65685424949238, 
    0.176776695296637, 0.176776695296637, 0.176776695296637, 
    0.176776695296637, 0.176776695296637, 0.176776695296637, 
    0.176776695296637, 0.176776695296637, 0.176776695296637, 
    0.176776695296637, 0.176776695296637, 0.176776695296637, 
    0.176776695296637, 0.176776695296637, 0.176776695296637, 
    0.176776695296637, 0.176776695296637, 0.176776695296637, 
    0.176776695296637, 0.176776695296637, 0.176776695296637, 
    0.176776695296637, 0.176776695296637, 0.176776695296637, 
    0.176776695296637, 0.176776695296637, 0.176776695296637, 
    0.176776695296637, 0.176776695296637, 0.176776695296637, 
    0.176776695296637, -18.1995143341794, 5.44782048162382, 0.148230002781619, 
    -0.0160558805397839, -0.0573568009278461, -0.0610279938512294, 
    -0.0812195549298376, -0.0114668893855548, -0.00412450353878817, 
    -0.0573568009278461, -0.0573568009278461, -0.17299937801442, 
    -0.110589098316904, -0.119767080625362, -0.389599760494035, 
    -0.42153913892747, -0.407037926880106, 0.170257160321919, 
    0.27763955333088, 0.237256431173664, 0.12161385408709, -0.0720415726213793, 
    -0.0564390026970003, -0.130780659395512, -0.131698457626358, 
    0.218900466556748, 0.181270739092069, 0.296362637240135, 
    -0.00779569646217148, 0.0656281620054946, -0.0812195549298376, 
    0.063792565543803), .Dim = c(32L, 2L), .Dimnames = list(c("Mazda RX4", 
    "Mazda RX4 Wag", "Datsun 710", "Hornet 4 Drive", "Hornet Sportabout", 
    "Valiant", "Duster 360", "Merc 240D", "Merc 230", "Merc 280", 
    "Merc 280C", "Merc 450SE", "Merc 450SL", "Merc 450SLC", "Cadillac Fleetwood", 
    "Lincoln Continental", "Chrysler Imperial", "Fiat 128", "Honda Civic", 
    "Toyota Corolla", "Toyota Corona", "Dodge Challenger", "AMC Javelin", 
    "Camaro Z28", "Pontiac Firebird", "Fiat X1-9", "Porsche 914-2", 
    "Lotus Europa", "Ford Pantera L", "Ferrari Dino", "Maserati Bora", 
    "Volvo 142E"), c("(Intercept)", "wt")), assign = 0:1), qraux = c(1.17677669529664, 
    1.04635439915773), pivot = 1:2, tol = 1e-07, rank = 2L), .Names = c("qr", 
    "qraux", "pivot", "tol", "rank"), class = "qr"), df.residual = 30L, 
    xlevels = structure(list(), .Names = character(0)), call = lm(formula = mpg ~ 
        wt, data = mtcars), terms = mpg ~ wt, model = structure(list(
        mpg = c(21, 21, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.8, 
        19.2, 17.8, 16.4, 17.3, 15.2, 10.4, 10.4, 14.7, 32.4, 
        30.4, 33.9, 21.5, 15.5, 15.2, 13.3, 19.2, 27.3, 26, 30.4, 
        15.8, 19.7, 15, 21.4), wt = c(2.62, 2.875, 2.32, 3.215, 
        3.44, 3.46, 3.57, 3.19, 3.15, 3.44, 3.44, 4.07, 3.73, 
        3.78, 5.25, 5.424, 5.345, 2.2, 1.615, 1.835, 2.465, 3.52, 
        3.435, 3.84, 3.845, 1.935, 2.14, 1.513, 3.17, 2.77, 3.57, 
        2.78)), .Names = c("mpg", "wt"), terms = mpg ~ wt, row.names = c("Mazda RX4", 
    "Mazda RX4 Wag", "Datsun 710", "Hornet 4 Drive", "Hornet Sportabout", 
    "Valiant", "Duster 360", "Merc 240D", "Merc 230", "Merc 280", 
    "Merc 280C", "Merc 450SE", "Merc 450SL", "Merc 450SLC", "Cadillac Fleetwood", 
    "Lincoln Continental", "Chrysler Imperial", "Fiat 128", "Honda Civic", 
    "Toyota Corolla", "Toyota Corona", "Dodge Challenger", "AMC Javelin", 
    "Camaro Z28", "Pontiac Firebird", "Fiat X1-9", "Porsche 914-2", 
    "Lotus Europa", "Ford Pantera L", "Ferrari Dino", "Maserati Bora", 
    "Volvo 142E"), class = "data.frame")), .Names = c("coefficients", 
"residuals", "effects", "rank", "fitted.values", "assign", "qr", 
"df.residual", "xlevels", "call", "terms", "model"), class = "lm")), .Names = c("nums", 
"y", "x", "model"))
# 2nd element in tricky_list
tricky_list[[2]]
##  [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
typeof(tricky_list[[2]])
## [1] "logical"
# Element called x in tricky_list
tricky_list[["x"]]
## [[1]]
## [1] "hello!"
## 
## [[2]]
## [1] "hi!"
## 
## [[3]]
## [1] "goodbye!"
## 
## [[4]]
## [1] "bye!"
typeof(tricky_list[["x"]])
## [1] "list"
# 2nd element inside the element called x in tricky_list
tricky_list[["x"]][[2]]
## [1] "hi!"
typeof(tricky_list[["x"]][[2]])
## [1] "character"

9.1.7.3 Explorando listas

A menudo no es necesario que veamos el contenido albertado en las listas, sino conocer sus atributos para saber cómo están formadas. Para ello podemos usar las funciones str() y names().

# Guess where the regression model is stored
names(tricky_list)
## [1] "nums"  "y"     "x"     "model"
# Use names() and str() on the model element
names(tricky_list[["model"]])
##  [1] "coefficients"  "residuals"     "effects"       "rank"         
##  [5] "fitted.values" "assign"        "qr"            "df.residual"  
##  [9] "xlevels"       "call"          "terms"         "model"
str(tricky_list[["model"]])
## List of 12
##  $ coefficients : Named num [1:2] 37.29 -5.34
##   ..- attr(*, "names")= chr [1:2] "(Intercept)" "wt"
##  $ residuals    : Named num [1:32] -2.28 -0.92 -2.09 1.3 -0.2 ...
##   ..- attr(*, "names")= chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
##  $ effects      : Named num [1:32] -113.65 -29.116 -1.661 1.631 0.111 ...
##   ..- attr(*, "names")= chr [1:32] "(Intercept)" "wt" "" "" ...
##  $ rank         : int 2
##  $ fitted.values: Named num [1:32] 23.3 21.9 24.9 20.1 18.9 ...
##   ..- attr(*, "names")= chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
##  $ assign       : int [1:2] 0 1
##  $ qr           :List of 5
##   ..$ qr   : num [1:32, 1:2] -5.657 0.177 0.177 0.177 0.177 ...
##   .. ..- attr(*, "dimnames")=List of 2
##   .. .. ..$ : chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
##   .. .. ..$ : chr [1:2] "(Intercept)" "wt"
##   .. ..- attr(*, "assign")= int [1:2] 0 1
##   ..$ qraux: num [1:2] 1.18 1.05
##   ..$ pivot: int [1:2] 1 2
##   ..$ tol  : num 1e-07
##   ..$ rank : int 2
##   ..- attr(*, "class")= chr "qr"
##  $ df.residual  : int 30
##  $ xlevels      : Named list()
##  $ call         :List of 12
##   ..$ coefficients : Named num [1:2] 37.29 -5.34
##   .. ..- attr(*, "names")= chr [1:2] "(Intercept)" "wt"
##   ..$ residuals    : Named num [1:32] -2.28 -0.92 -2.09 1.3 -0.2 ...
##   .. ..- attr(*, "names")= chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
##   ..$ effects      : Named num [1:32] -113.65 -29.116 -1.661 1.631 0.111 ...
##   .. ..- attr(*, "names")= chr [1:32] "(Intercept)" "wt" "" "" ...
##   ..$ rank         : int 2
##   ..$ fitted.values: Named num [1:32] 23.3 21.9 24.9 20.1 18.9 ...
##   .. ..- attr(*, "names")= chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
##   ..$ assign       : int [1:2] 0 1
##   ..$ qr           :List of 5
##   .. ..$ qr   : num [1:32, 1:2] -5.657 0.177 0.177 0.177 0.177 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
##   .. .. .. ..$ : chr [1:2] "(Intercept)" "wt"
##   .. .. ..- attr(*, "assign")= int [1:2] 0 1
##   .. ..$ qraux: num [1:2] 1.18 1.05
##   .. ..$ pivot: int [1:2] 1 2
##   .. ..$ tol  : num 1e-07
##   .. ..$ rank : int 2
##   .. ..- attr(*, "class")= chr "qr"
##   ..$ df.residual  : int 30
##   ..$ xlevels      : Named list()
##   ..$ call         : language lm(formula = mpg ~ wt, data = mtcars)
##   ..$ terms        :Classes 'terms', 'formula'  language mpg ~ wt
##   .. .. ..- attr(*, "variables")= language list(mpg, wt)
##   .. .. ..- attr(*, "factors")= int [1:2, 1] 0 1
##   .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. ..$ : chr [1:2] "mpg" "wt"
##   .. .. .. .. ..$ : chr "wt"
##   .. .. ..- attr(*, "term.labels")= chr "wt"
##   .. .. ..- attr(*, "order")= int 1
##   .. .. ..- attr(*, "intercept")= int 1
##   .. .. ..- attr(*, "response")= int 1
##   .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
##   .. .. ..- attr(*, "predvars")= language list(mpg, wt)
##   .. .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
##   .. .. .. ..- attr(*, "names")= chr [1:2] "mpg" "wt"
##   ..$ model        :'data.frame':    32 obs. of  2 variables:
##   .. ..$ mpg: num [1:32] 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##   .. ..$ wt : num [1:32] 2.62 2.88 2.32 3.21 3.44 ...
##   .. ..- attr(*, "terms")=Classes 'terms', 'formula'  language mpg ~ wt
##   .. .. .. ..- attr(*, "variables")= language list(mpg, wt)
##   .. .. .. ..- attr(*, "factors")= int [1:2, 1] 0 1
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:2] "mpg" "wt"
##   .. .. .. .. .. ..$ : chr "wt"
##   .. .. .. ..- attr(*, "term.labels")= chr "wt"
##   .. .. .. ..- attr(*, "order")= int 1
##   .. .. .. ..- attr(*, "intercept")= int 1
##   .. .. .. ..- attr(*, "response")= int 1
##   .. .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
##   .. .. .. ..- attr(*, "predvars")= language list(mpg, wt)
##   .. .. .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
##   .. .. .. .. ..- attr(*, "names")= chr [1:2] "mpg" "wt"
##   ..- attr(*, "class")= chr "lm"
##  $ terms        :Class 'formula'  language mpg ~ wt
##   .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
##  $ model        :'data.frame':   32 obs. of  2 variables:
##   ..$ mpg: num [1:32] 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##   ..$ wt : num [1:32] 2.62 2.88 2.32 3.21 3.44 ...
##   ..- attr(*, "terms")=Class 'formula'  language mpg ~ wt
##   .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
##  - attr(*, "class")= chr "lm"
# Subset the coefficients element
tricky_list[["model"]][["coefficients"]]
## (Intercept)          wt 
##   37.285126   -5.344472
# Subset the wt element
tricky_list[["model"]][["coefficients"]][["wt"]]
## [1] -5.344472

9.1.7.4 for loops

Revisamos el curso 2 con el for loop. Los for loops sirven para iterar repetidamente y están formados por tres partes:

  • Secuencia: que incluye dos cosas, el nombre que le daremos al objeto que indexa la iteración (normalmente i) y el número de veces que tiene que iterar el loop.
  • Cuerpo: que se sitúa entre llames y define las funciones a realizar cada vez que se itere.
  • Output: se indica cómo se van a guardar estos resultados.

Si queremos iterar sobre las columnas de un data frame escribimos (i in 1:ncol(df))

Let’s take a look at the sequence component of our for loop:

i in 1:ncol(df)

Each time our for loop iterates, i takes the next value in 1:ncol(df). This is a pretty common model for a sequence: a sequence of consecutive integers designed to index over one dimension of our data.

What might surprise you is that this isn’t the best way to generate such a sequence, especially when you are using for loops inside your own functions. Let’s look at an example where df is an empty data frame (esto da un error):

df <- data.frame()
1:ncol(df)

for (i in 1:ncol(df)) {
  print(median(df[[i]]))
}

Our sequence is now the somewhat non-sensical: 1, 0. You might think you wouldn’t be silly enough to use a for loop with an empty data frame, but once you start writing your own functions, there’s no telling what the input will be.

A better method is to use the seq_along() function. This function generates a sequence along the index of the object passed to it, but handles the empty case much better.

# Create an empty data frame
empty_df <- data.frame()

# Repeat for loop to verify there is no error
for (i in seq_along(empty_df)) {
  print(median(empty_df[[i]]))
}

Our for loop does a good job displaying the column medians, but we might want to store these medians in a vector for future use.

Before you start the loop, you must always allocate sufficient space for the output, let’s say an object called output. This is very important for efficiency: if you grow the for loop at each iteration (e.g. using c()), your for loop will be very slow.

A general way of creating an empty vector of given length is the vector() function. It has two arguments: the type of the vector (“logical”, “integer”, “double”, “character”, etc.) and the length of the vector.

Then, at each iteration of the loop you must store the output in the corresponding entry of the output vector, i.e. assign the result to output[[i]]. (You might ask why we are using double brackets here when output is a vector. It’s primarily for generalizability: this subsetting will work whether output is a vector or a list.)

Let’s edit our loop to store the medians, rather than printing them to the console.

# Create new double vector: output
output <- vector("double", ncol(df))

# Alter the loop
for (i in seq_along(df)) {
  # Change code to store result in output
  output[i] <- median(df[[i]])
}

# Print output
output
## [1] NA NA 18

9.2 Cuándo y cómo debemos escribir una función

Básicamente, cuando hagamos copiar y pegar código para repetir acciones en diferentes partes.

El primer paso para convertir un código en una función es identificar cuántos inputs existen. En este caso vemos que solo x es el input, por lo que solo hay 1.

# Define example vector x
x <- c(1:10, NA)

# Rewrite this snippet to refer to x
(x - min(x, na.rm = TRUE)) /
  (max(x, na.rm = TRUE) - min(x, na.rm = TRUE))
##  [1] 0.0000000 0.1111111 0.2222222 0.3333333 0.4444444 0.5555556 0.6666667
##  [8] 0.7777778 0.8888889 1.0000000        NA

El segundo paso es examinar el código para ver si se puede escribir de un modo más sencillo. Para ello vamos a fijarnos en los duplicados. Vemos que min(x, na.rm = TRUE) está repetido DOS veces. Tiene más sentido si esta información duplicada la almacenamos fuera.

# Defininmos el vector x
x <- c(1:10, NA)

# Definimos rng con la función range()
rng <- range(x, na.rm = TRUE)

# Reescribimos el código teniendo en cuenta rng
(x - min(rng)) /
  (max(rng) - min(rng))
##  [1] 0.0000000 0.1111111 0.2222222 0.3333333 0.4444444 0.5555556 0.6666667
##  [8] 0.7777778 0.8888889 1.0000000        NA

El tercer y último paso es escribir la función como tal. La llamaremos rescale01()

# Test your function, call rescale01 using the vector x as the argument
rescale01 <- function(x){
   rng <- range(x, na.rm = TRUE) 
   (x - rng[1]) / (rng[2] - rng[1]) 
}

rescale01(x)
##  [1] 0.0000000 0.1111111 0.2222222 0.3333333 0.4444444 0.5555556 0.6666667
##  [8] 0.7777778 0.8888889 1.0000000        NA

9.2.1 ¿Cómo debemos escribir una función?

Primero comenzar con un problema simple. A continuación crear un pequeño snipped de código, pudiendo incluir variables temporales. Reescribir todo para unifircarlo y finalmente escribir la función. Despues de escribirla hay que testearla. Resumiendo:

  • Comenzar con un problema simple.
  • Get a working snipped of code.
  • Reescribir para emplear variables temporales.
  • Reescribir para que sea más claro.
  • Convertirlo en una función.

9.2.1.1 Comenzamos con un problema simple

Queremos generar una función que nos indique cuántas veces en una posición de dos vectores aparece un NA.

# Definimos los dos vectores. Como vemos, solo hay una posición donde los dos vectores son NA.
x <- c( 1, 2, NA, 3, NA)
y <- c(NA, 3, NA, 3,  4)

# Vamos al problema simple. Vamos a contar cuántos elementos faltan en los dos
sum(is.na(x) & is.na(y))
## [1] 1

9.2.1.2 Rewrite a snippet as function

Ya hemos averiguado que tenemos dos inputs (los dos vectores) y les hemos dado dos valores razonables. El código es tan claro que no podemos simplificarlo más. Así que vamos a convertirlo en una función.

both_na <- function(x, y) {
  sum(is.na(x) & is.na(y))
}

9.2.1.3 Testeamos su funcionamiento

# Definimos nuevos vectores para ver cómo funciona
x <-  c(NA, NA, NA)
y1 <- c( 1, NA, NA)
y2 <- c( 1, NA, NA, NA)

# Hacemos una comparación
both_na(x, y1)
## [1] 2
# Hacemos una segunda comparación
both_na(x, y2)
## Warning in is.na(x) & is.na(y): longer object length is not a multiple of
## shorter object length
## [1] 3

Vemos que el último ejemplo el resultado no ha sido el esperado. Esto ha sido porque el número de elementos ha sido diferente. A continuación vamos a ver cómo solucionarlo.

9.2.2 ¿Cómo podemos escribir una buena función?

Obviamente, debe dar resultados correctos, tiene que ser comprensible pero no solo para R, sino también para el resto de los humanos. En este context, que sea correcta y comprensible hace que sea una buena función.

Principios para dar nombre a una función:

  • Dar buenos nombres a las funciones hace que el código sea comprensible con el mínimo contexto.
  • Los nombres largos deben escribirse con guiones bajos (_) para separar entre palabras.
  • No dar nombres a nuestra función cuyo nombre ya esté en otra función, para no sobreescribirla.
  • También es recomendable que incluyan verbos, puesto que las funciones hacen algo.
  • El nombre debe describir su funcionamiento.

Principios para dar nombre a los argumentos:

  • Deben ser nombres.
  • Usar los que son muy comunies y apropiados (x, y, z, df, i, j, n, p…).
  • Escribir en orden los argumentos, comenzando por los que no tienen valor y finalizando por los que tienen un valor preasignado.

Por lo tanto:

  • Debemos usar buenos nombres para las funciones y argumentos.
  • Usar un orden intuitivo de los argmentos y valores predeterminados que sean razonables.
  • Dejar claro lo que devuelve la función.
  • Usar un buen estilo dentro del cuerpo de la función.

## Uso de return()

# Función sin el return y resultado con un vector vacío 
mean_ci <- function(x, level = 0.95) {
  se <- sd(x) / sqrt(length(x))
  alpha <- 1 - level
  mean(x) + se * qnorm(c(alpha / 2, 1 - alpha / 2))
}

x <- c()
mean_ci(x)
## Warning in mean.default(x): argument is not numeric or logical: returning
## NA
## [1] NA NA
# Introducimos el return
mean_ci <- function(x, level = 0.95) {
  if(length(x)==0){
    return(c(-Inf, Inf))
  }
  se <- sd(x) / sqrt(length(x))
  alpha <- 1 - level
  mean(x) + se * qnorm(c(alpha / 2, 1 - alpha / 2))
}

x <- c()
mean_ci(x)
## [1] -Inf  Inf

En el primer caso, si el vector no tiene valores (c()), te devuelve un c(NA, NA). Para evitar esto y que esté mejor escrito, en el segundo ejemplo ponemos la función con un if{} en el que le indicamos que si el objeto tiene longitud 0, nos devuelva con return() el vector c(-Inf, Inf).

9.2.3 Arreglando una funcińo

Vamos a poner una función mal estructurada. Esta función lo que hace es sustituir los valores NA de un vector por el valor de y.

f <- function(x, y) {
  x[is.na(x)] <- y
  cat(sum(is.na(x)), y, "\n")
  x
}

x <- c(1, 3, NA, NA, 6, 7, NA)

f(x, 30)
## 0 30
## [1]  1  3 30 30  6  7 30

Primero, debemos renombrar la función, por ejemplo, con replace_missings(). También vamos a renombrar el argumento y con replacement. Quedaría así la función, algo más comprensible para el usuario.

replace_missings <- function(x, replacement) {
  x[is.na(x)] <- replacement
  cat(sum(is.na(x)), replacement, "\n")
  x
}

Aun así se puede optimizar el cuerpo de la función para evitar duplicados, como vamos a ver a continuación, llamando is_miss <- is.na(x).

replace_missings <- function(x, replacement) {
  is_miss <- is.na(x)
  x[is_miss] <- replacement
  cat(sum(is_miss), replacement, "\n")
  x
}

9.3 Programación funcional

Está basado en saber dónde está lo común y lo diferente entre funciones. Básicamente es comprender que una función puede ser un argumento de otra función.

# Imaginemos que tenemos este dataframe
df <- data.frame(
  a = rnorm(10),
  b = rnorm(10),
  c = rnorm(10),
  d = rnorm(10)
)

# Y queremos calcular la mediana de cada columna
median(df[[1]])
## [1] 0.313229
median(df[[2]])
## [1] 0.6626114
median(df[[3]])
## [1] -0.09436136
median(df[[4]])
## [1] 0.2016101

Como vemos, hay mucha repetición, ya que ejecutamos cada función median() varias vece. Vamos a intentar solucionarlo con un for loop

# Initialize output vector
output <- numeric(ncol(df))

# Fill in the body of the for loop
for (i in seq_along(df)) {            
  output[[i]] <- median(df[[i]])
}

# View the result
output
## [1]  0.31322901  0.66261144 -0.09436136  0.20161009

Ahora convertimos el for loop en una función, ya que supongamos que tuviésemos un df2, df3… ¡Es momento de crear una función!

# Turn this code into col_median()
col_median <- function(df) {
  output <- numeric(ncol(df))
  for (i in seq_along(df)) {
    output[[i]] <- median(df[[i]])
  }
  output
}

# Change col_median() to a col_mean() function to find column means
col_mean <- function(df) {
  output <- numeric(ncol(df))
  for (i in seq_along(df)) {
    output[[i]] <- mean(df[[i]])
  }
  output
}

# Define col_sd() function
col_sd <- function(df) {
  output <- numeric(ncol(df))
  for (i in seq_along(df)) {
    output[[i]] <- sd(df[[i]])
  }
  output
}

Pongamos que tenemos esta situación, en la que creamos tres funciones para calcular las desviaciones de la media a la potencia 1, 2 y 3. Fijémonos que hemos copiado/pegado tres veces. ¿Cómo podemos evitar este copiar/pegar?

# Las tres funciones:
f1 <- function(x) abs(x - mean(x)) ^ 1
f2 <- function(x) abs(x - mean(x)) ^ 2
f3 <- function(x) abs(x - mean(x)) ^ 3

# Función alternativa integrando la potencia
f <- function(x, power) {
    # Edit the body to return absolute deviations raised to power
    abs(x - mean(x))^power
}

Esto indica que podemos eliminar duplicados con argumentos.

9.3.1 Funciones como argumentos

Podemos incluir funciones como argumentos dentro de otras funciones. Para ello, vamos a ver el ejemplo anterior:

# Turn this code into col_median()
col_median <- function(df) {
  output <- numeric(ncol(df))
  for (i in seq_along(df)) {
    output[[i]] <- median(df[[i]])
  }
  output
}

# Change col_median() to a col_mean() function to find column means
col_mean <- function(df) {
  output <- numeric(ncol(df))
  for (i in seq_along(df)) {
    output[[i]] <- mean(df[[i]])
  }
  output
}

# Define col_sd() function
col_sd <- function(df) {
  output <- numeric(ncol(df))
  for (i in seq_along(df)) {
    output[[i]] <- sd(df[[i]])
  }
  output
}

Aquí vemos que la diferencia entre los 3 se encuentra solo en mean(), median() y sd(). El resto del código de las funciones está duplicado. Vamos a solucionarlo añadiendo el argumento fun, que puede tomar valores mean, median, sd u otros. Además, renombramos la función a col_summary().

col_summary <- function(df, fun) {
  output <- numeric(ncol(df))
  for (i in seq_along(df)) {
    output[[i]] <- fun(df[[i]])
  }
  output
}

# Find the column medians using col_median() and col_summary()
col_summary(df,median)
## [1]  0.31322901  0.66261144 -0.09436136  0.20161009
# Find the column means using col_mean() and col_summary()
col_summary(df,mean)
## [1] 0.34691674 0.55586302 0.01050904 0.06337469
# Find the column IQRs using col_summary()
col_summary(df, IQR)
## [1] 1.4799512 1.3420958 1.0214612 0.9653429

9.3.2 Introduciendo el paquete purrr

Lo último que hemos hecho ha sido pasar como un argumento a una función con col_summary(). Pero esto mismo lo podemos hacer la función sapply(). Digamos que con nuestra función hemos conseguido realizar y aproximarnos a esta última.

sapply(df, mean)
##          a          b          c          d 
## 0.34691674 0.55586302 0.01050904 0.06337469

Sin embargo, también podemos hacerlos con las funciones map del paquete purrr.

library(purrr)
## 
## Attaching package: 'purrr'
## The following object is masked from 'package:jsonlite':
## 
##     flatten
## The following object is masked from 'package:gdata':
## 
##     keep
## The following object is masked from 'package:data.table':
## 
##     transpose
map_dbl(df, mean)
##          a          b          c          d 
## 0.34691674 0.55586302 0.01050904 0.06337469

Todas las funciones map tienen la misma estructura:

map_dbl(.x, .f, ...)
  • Se hace un loop en el vector .x
  • Se aplica una función .f
  • Nos devuelve el resultado

Existe una función map para cada tipo de vector:

  • map() devuelve una lista.
  • map_dbl() devuelve un vector double.
  • map_lgl() devuelve un vector lógico.
  • map_int() devuelve un vector enter (integer).
  • map_chr() devuelve un vector carácter.
# Use map_dbl() to find column means
map_dbl(df, mean)
##          a          b          c          d 
## 0.34691674 0.55586302 0.01050904 0.06337469
# Use map_dbl() to column medians
map_dbl(df, median)
##           a           b           c           d 
##  0.31322901  0.66261144 -0.09436136  0.20161009
# Use map_dbl() to find column standard deviations
map_dbl(df, sd)
##         a         b         c         d 
## 0.9900227 0.8141140 0.6565991 1.0802889

El uso del argumento ... nos permite incluir otras opciones para la función o los datos.

map_dbl(df, mean, trim = 0.5)
##           a           b           c           d 
##  0.31322901  0.66261144 -0.09436136  0.20161009
map_dbl(df, mean, trim = 0.5, na.rm = TRUE)
##           a           b           c           d 
##  0.31322901  0.66261144 -0.09436136  0.20161009

You may be wondering why the arguments to map() are .x and .f and not x and f? It’s because .x and .f are very unlikely to be argument names you might pass through the …, thereby preventing confusion about whether an argument belongs to map() or to the function being mapped.

Picking the right map function

Choosing the right map function is important. You can always use map(), which will return a list. However, if you know what type of output you expect, you are better to use the corresponding function. That way, if you expect one thing and get another, you’ll know immediately because the map function will return an error.

For example, try running:

map_lgl(df, mean)

The map functions are what we call type consistent. This means you know exactly what type of output to expect regardless of the input. map_lgl() either returns either a logical vector or an error. map_dbl() returns either a double or an error.

One way to check the output type is to run the corresponding function on the first element. For example, mean(df[[1]]) returns a single numeric value, suggesting map_dbl().

Let’s get some more practice with the map functions. We’ve created a new data frame, df3, in your workspace. Use a map function to find which columns are numeric, the type of each column, and a summary of each column.

9.3.3 Shortcust de .f (del paquete purrr)

Hemos visto en las funciones map(), pasamos una función en el argumento .f. Sin embargo, algunas veces queremos llamar a una serie de funciones, o una función donde el argumento que queremos cambiar no es el primer argumento. Una solución es crear la función directamente dentro del argumento .f.

map(df, function(x) sum(is.na(x)))

9.3.3.1 Shortcuts para funciones anónimas

El primer shortcut que vamos a ver está diseñado para realizar lo mismo que antes pero con mucho menos código. Este shortcode convierte la función anónima en una fórmula, y donde estaba el valor x ahora ponemos un punto ..

map(df, ~ sum(is.na(.)))

9.3.3.2 Shortcuts cuando .f es [[]]

El segundo shortcut está relacionado con creación de subconjuntos [[]]. Tenemos una lista como la siguiente.

list_results <- list(
  list(a = 1, b = "A"),
  list(a = 2, b = "C"),
  list(a = 3, b = "D")
)
library(purrr)

# Vemos sin usar el shortcode
map_dbl(list_results, function(x) x[["a"]])
## [1] 1 2 3
# Y ahora usando los shortcodes para mostrar el primer elemento de cada lista
map_dbl(list_results, "a")
## [1] 1 2 3
map_dbl(list_results, 1)
## [1] 1 2 3

9.3.3.3 Lista de dataframes

Vamos con un ejemplo algo más complejo.

data("mtcars")

# Dividimos los datos en subconjuntos según la columna cyl
cyl <- split(mtcars, mtcars$cyl)

Vemos que el objeto recién creado cyl es una lista, que contiene 3 dataframes, cada uno con el número de cilindros de los coches. Un dataframe para los 4 cilindros, otro para los 6 cilindros y por último el de 8 cilindros. Todos estos dataframes tienen el mismo número de columnas, como mtcars.

El objetivo a continuación es ajustar una regresión para cada dataframe, enfrentando mpg (miles per gallon, fuel efficiency) a wt (peso). El vector de las pendientes es nuestro objetivo.

# Examinamos la estructura de cyl
str(cyl)
## List of 3
##  $ 4:'data.frame':   11 obs. of  11 variables:
##   ..$ mpg : num [1:11] 22.8 24.4 22.8 32.4 30.4 33.9 21.5 27.3 26 30.4 ...
##   ..$ cyl : num [1:11] 4 4 4 4 4 4 4 4 4 4 ...
##   ..$ disp: num [1:11] 108 146.7 140.8 78.7 75.7 ...
##   ..$ hp  : num [1:11] 93 62 95 66 52 65 97 66 91 113 ...
##   ..$ drat: num [1:11] 3.85 3.69 3.92 4.08 4.93 4.22 3.7 4.08 4.43 3.77 ...
##   ..$ wt  : num [1:11] 2.32 3.19 3.15 2.2 1.61 ...
##   ..$ qsec: num [1:11] 18.6 20 22.9 19.5 18.5 ...
##   ..$ vs  : num [1:11] 1 1 1 1 1 1 1 1 0 1 ...
##   ..$ am  : num [1:11] 1 0 0 1 1 1 0 1 1 1 ...
##   ..$ gear: num [1:11] 4 4 4 4 4 4 3 4 5 5 ...
##   ..$ carb: num [1:11] 1 2 2 1 2 1 1 1 2 2 ...
##  $ 6:'data.frame':   7 obs. of  11 variables:
##   ..$ mpg : num [1:7] 21 21 21.4 18.1 19.2 17.8 19.7
##   ..$ cyl : num [1:7] 6 6 6 6 6 6 6
##   ..$ disp: num [1:7] 160 160 258 225 168 ...
##   ..$ hp  : num [1:7] 110 110 110 105 123 123 175
##   ..$ drat: num [1:7] 3.9 3.9 3.08 2.76 3.92 3.92 3.62
##   ..$ wt  : num [1:7] 2.62 2.88 3.21 3.46 3.44 ...
##   ..$ qsec: num [1:7] 16.5 17 19.4 20.2 18.3 ...
##   ..$ vs  : num [1:7] 0 0 1 1 1 1 0
##   ..$ am  : num [1:7] 1 1 0 0 0 0 1
##   ..$ gear: num [1:7] 4 4 3 3 4 4 5
##   ..$ carb: num [1:7] 4 4 1 1 4 4 6
##  $ 8:'data.frame':   14 obs. of  11 variables:
##   ..$ mpg : num [1:14] 18.7 14.3 16.4 17.3 15.2 10.4 10.4 14.7 15.5 15.2 ...
##   ..$ cyl : num [1:14] 8 8 8 8 8 8 8 8 8 8 ...
##   ..$ disp: num [1:14] 360 360 276 276 276 ...
##   ..$ hp  : num [1:14] 175 245 180 180 180 205 215 230 150 150 ...
##   ..$ drat: num [1:14] 3.15 3.21 3.07 3.07 3.07 2.93 3 3.23 2.76 3.15 ...
##   ..$ wt  : num [1:14] 3.44 3.57 4.07 3.73 3.78 ...
##   ..$ qsec: num [1:14] 17 15.8 17.4 17.6 18 ...
##   ..$ vs  : num [1:14] 0 0 0 0 0 0 0 0 0 0 ...
##   ..$ am  : num [1:14] 0 0 0 0 0 0 0 0 0 0 ...
##   ..$ gear: num [1:14] 3 3 3 3 3 3 3 3 3 3 ...
##   ..$ carb: num [1:14] 2 4 3 3 3 4 4 4 2 2 ...
# Extraemos el primer elemento de la lista (los de 4 cilindros)
four_cyls <- cyl[[1]]

# Ajustamos a un modelo lineal mpg y wt
lm(data = four_cyls, formula = mpg ~ wt)
## 
## Call:
## lm(formula = mpg ~ wt, data = four_cyls)
## 
## Coefficients:
## (Intercept)           wt  
##      39.571       -5.647

Ya tenemos escrito el código para hacer el modelo lineal. Vamos a convertirlo a una función.

fit_reg <- function(df) {
  lm(mpg ~ wt, data = df)
}

Y ahora lo pasamos a map()

map(cyl, fit_reg)
## $`4`
## 
## Call:
## lm(formula = mpg ~ wt, data = df)
## 
## Coefficients:
## (Intercept)           wt  
##      39.571       -5.647  
## 
## 
## $`6`
## 
## Call:
## lm(formula = mpg ~ wt, data = df)
## 
## Coefficients:
## (Intercept)           wt  
##       28.41        -2.78  
## 
## 
## $`8`
## 
## Call:
## lm(formula = mpg ~ wt, data = df)
## 
## Coefficients:
## (Intercept)           wt  
##      23.868       -2.192

Sin embargo, escribir la función y luego aplicarla parece mucho código. Vamos a incorporarla anónimamente a map()

map(cyl, function(df) lm(mpg ~ wt, data = df))

Sin embargo, purrr nos permite introducir shortcuts e introducir funciones como sin fueran fórmulas de un solo lado.

map(cyl, ~lm(mpg ~ wt, data = .))
## $`4`
## 
## Call:
## lm(formula = mpg ~ wt, data = .)
## 
## Coefficients:
## (Intercept)           wt  
##      39.571       -5.647  
## 
## 
## $`6`
## 
## Call:
## lm(formula = mpg ~ wt, data = .)
## 
## Coefficients:
## (Intercept)           wt  
##       28.41        -2.78  
## 
## 
## $`8`
## 
## Call:
## lm(formula = mpg ~ wt, data = .)
## 
## Coefficients:
## (Intercept)           wt  
##      23.868       -2.192

Vamos a extraer ahora solo las pendientes, usando en un principio coef() para extraer los coeficientes (incluidas las pendientes).

# Save the result from the previous exercise to the variable models
models <- map(cyl, ~ lm(mpg ~ wt, data = .))

# Use map and coef to get the coefficients for each model: coefs
coefs <- map(models, coef)

# Use string shortcut to extract the wt coefficient 
map(coefs, "wt")
## $`4`
## [1] -5.647025
## 
## $`6`
## [1] -2.780106
## 
## $`8`
## [1] -2.192438

Otra forma es indicando la posición del elemento. Vamos a extraer las pendientes usando su posición dentro de los coeficientes, que es la segunda.

map_dbl(coefs, 2)
##         4         6         8 
## -5.647025 -2.780106 -2.192438

9.3.4 Uniendo todo con pipes (%>%) en purrr

El paquete purrr también puede integrarse con pipes (%>%). Todo el proceso anterior, desde el split() de mtcars hasta la obtención de las pendientes quedaría así usando pipes.

mtcars %>% 
  split(mtcars$cyl) %>%
  map(~ lm(mpg ~ wt, data = .)) %>%
  map(coef) %>% 
  map_dbl("wt")
##         4         6         8 
## -5.647025 -2.780106 -2.192438

Esto se puede leer así: coge mtcars y dividelo con split() según cilindros. Con el resultado, haz map(), etc.

9.4 Advanced inputs y outputs

9.4.1 Qué hacer con los errores

Cuando en el proceso de iteración falla un valor, el proceso completo genera un error y no conoces dónde se ha producido. Es bastante frustrante. Sin embargo, purrr ofrece alternativas para poder salvar estas situaciones.

9.4.1.1 safely()

safely() es un adverbio que modifica el verbo. Es decir, toma como argumento una función y devuelve una función. Esta función que sale es modificada por lo que nunca muestra un error y nunca se para en los procesos de iteración. Siempre devuelve una lista de 2 elementos:

  • result, que es el resultado original. Si hay algún error, ese elemento aparecerá como NULL.
  • error, es un objeto que si el proceso de iteración ha sido correcto, devuelve NULL.
library(purrr)

# Create safe_readLines() by passing readLines() to safely()
safe_readLines <- safely(readLines)

# Call safe_readLines() on "http://example.org"
example_lines <- safe_readLines("http://example.org")
example_lines
## $result
##  [1] "<!doctype html>"                                                                                      
##  [2] "<html>"                                                                                               
##  [3] "<head>"                                                                                               
##  [4] "    <title>Example Domain</title>"                                                                    
##  [5] ""                                                                                                     
##  [6] "    <meta charset=\"utf-8\" />"                                                                       
##  [7] "    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />"                        
##  [8] "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />"                       
##  [9] "    <style type=\"text/css\">"                                                                        
## [10] "    body {"                                                                                           
## [11] "        background-color: #f0f0f2;"                                                                   
## [12] "        margin: 0;"                                                                                   
## [13] "        padding: 0;"                                                                                  
## [14] "        font-family: \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;"                
## [15] "        "                                                                                             
## [16] "    }"                                                                                                
## [17] "    div {"                                                                                            
## [18] "        width: 600px;"                                                                                
## [19] "        margin: 5em auto;"                                                                            
## [20] "        padding: 50px;"                                                                               
## [21] "        background-color: #fff;"                                                                      
## [22] "        border-radius: 1em;"                                                                          
## [23] "    }"                                                                                                
## [24] "    a:link, a:visited {"                                                                              
## [25] "        color: #38488f;"                                                                              
## [26] "        text-decoration: none;"                                                                       
## [27] "    }"                                                                                                
## [28] "    @media (max-width: 700px) {"                                                                      
## [29] "        body {"                                                                                       
## [30] "            background-color: #fff;"                                                                  
## [31] "        }"                                                                                            
## [32] "        div {"                                                                                        
## [33] "            width: auto;"                                                                             
## [34] "            margin: 0 auto;"                                                                          
## [35] "            border-radius: 0;"                                                                        
## [36] "            padding: 1em;"                                                                            
## [37] "        }"                                                                                            
## [38] "    }"                                                                                                
## [39] "    </style>    "                                                                                     
## [40] "</head>"                                                                                              
## [41] ""                                                                                                     
## [42] "<body>"                                                                                               
## [43] "<div>"                                                                                                
## [44] "    <h1>Example Domain</h1>"                                                                          
## [45] "    <p>This domain is established to be used for illustrative examples in documents. You may use this"
## [46] "    domain in examples without prior coordination or asking for permission.</p>"                      
## [47] "    <p><a href=\"http://www.iana.org/domains/example\">More information...</a></p>"                   
## [48] "</div>"                                                                                               
## [49] "</body>"                                                                                              
## [50] "</html>"                                                                                              
## 
## $error
## NULL
# Call safe_readLines() on "http://asdfasdasdkfjlda"
nonsense_lines <- safe_readLines("http://asdfasdasdkfjlda")
## Warning in file(con, "r"): URL 'http://asdfasdasdkfjlda/': status was
## 'Couldn't resolve host name'
nonsense_lines
## $result
## NULL
## 
## $error
## <simpleError in file(con, "r"): cannot open the connection to 'http://asdfasdasdkfjlda'>

Esta función trabaja muy bien con las funciones map().

# Pongamos esta lista de url
urls <- list(
  example = "http://example.org",
  rproj = "http://www.r-project.org"
)

# Y miremos qué sucede sin usar safely()
map(urls, readLines)
## $example
##  [1] "<!doctype html>"                                                                                      
##  [2] "<html>"                                                                                               
##  [3] "<head>"                                                                                               
##  [4] "    <title>Example Domain</title>"                                                                    
##  [5] ""                                                                                                     
##  [6] "    <meta charset=\"utf-8\" />"                                                                       
##  [7] "    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />"                        
##  [8] "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />"                       
##  [9] "    <style type=\"text/css\">"                                                                        
## [10] "    body {"                                                                                           
## [11] "        background-color: #f0f0f2;"                                                                   
## [12] "        margin: 0;"                                                                                   
## [13] "        padding: 0;"                                                                                  
## [14] "        font-family: \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;"                
## [15] "        "                                                                                             
## [16] "    }"                                                                                                
## [17] "    div {"                                                                                            
## [18] "        width: 600px;"                                                                                
## [19] "        margin: 5em auto;"                                                                            
## [20] "        padding: 50px;"                                                                               
## [21] "        background-color: #fff;"                                                                      
## [22] "        border-radius: 1em;"                                                                          
## [23] "    }"                                                                                                
## [24] "    a:link, a:visited {"                                                                              
## [25] "        color: #38488f;"                                                                              
## [26] "        text-decoration: none;"                                                                       
## [27] "    }"                                                                                                
## [28] "    @media (max-width: 700px) {"                                                                      
## [29] "        body {"                                                                                       
## [30] "            background-color: #fff;"                                                                  
## [31] "        }"                                                                                            
## [32] "        div {"                                                                                        
## [33] "            width: auto;"                                                                             
## [34] "            margin: 0 auto;"                                                                          
## [35] "            border-radius: 0;"                                                                        
## [36] "            padding: 1em;"                                                                            
## [37] "        }"                                                                                            
## [38] "    }"                                                                                                
## [39] "    </style>    "                                                                                     
## [40] "</head>"                                                                                              
## [41] ""                                                                                                     
## [42] "<body>"                                                                                               
## [43] "<div>"                                                                                                
## [44] "    <h1>Example Domain</h1>"                                                                          
## [45] "    <p>This domain is established to be used for illustrative examples in documents. You may use this"
## [46] "    domain in examples without prior coordination or asking for permission.</p>"                      
## [47] "    <p><a href=\"http://www.iana.org/domains/example\">More information...</a></p>"                   
## [48] "</div>"                                                                                               
## [49] "</body>"                                                                                              
## [50] "</html>"                                                                                              
## 
## $rproj
##   [1] "<!DOCTYPE html>"                                                                                                                                                                                                                                                                                                                                     
##   [2] "<html lang=\"en\">"                                                                                                                                                                                                                                                                                                                                  
##   [3] "  <head>"                                                                                                                                                                                                                                                                                                                                            
##   [4] "    <meta charset=\"utf-8\">"                                                                                                                                                                                                                                                                                                                        
##   [5] "    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">"                                                                                                                                                                                                                                                                                       
##   [6] "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"                                                                                                                                                                                                                                                                        
##   [7] "    <title>R: The R Project for Statistical Computing</title>"                                                                                                                                                                                                                                                                                       
##   [8] ""                                                                                                                                                                                                                                                                                                                                                    
##   [9] "    <link rel=\"icon\" type=\"image/png\" href=\"/favicon-32x32.png\" sizes=\"32x32\" />"                                                                                                                                                                                                                                                            
##  [10] "    <link rel=\"icon\" type=\"image/png\" href=\"/favicon-16x16.png\" sizes=\"16x16\" />"                                                                                                                                                                                                                                                            
##  [11] ""                                                                                                                                                                                                                                                                                                                                                    
##  [12] "    <!-- Bootstrap -->"                                                                                                                                                                                                                                                                                                                              
##  [13] "    <link href=\"/css/bootstrap.min.css\" rel=\"stylesheet\">"                                                                                                                                                                                                                                                                                       
##  [14] "    <link href=\"/css/R.css\" rel=\"stylesheet\">"                                                                                                                                                                                                                                                                                                   
##  [15] ""                                                                                                                                                                                                                                                                                                                                                    
##  [16] "    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->"                                                                                                                                                                                                                                                          
##  [17] "    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->"                                                                                                                                                                                                                                                                      
##  [18] "    <!--[if lt IE 9]>"                                                                                                                                                                                                                                                                                                                               
##  [19] "      <script src=\"https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js\"></script>"                                                                                                                                                                                                                                                             
##  [20] "      <script src=\"https://oss.maxcdn.com/respond/1.4.2/respond.min.js\"></script>"                                                                                                                                                                                                                                                                 
##  [21] "    <![endif]-->"                                                                                                                                                                                                                                                                                                                                    
##  [22] "  </head>"                                                                                                                                                                                                                                                                                                                                           
##  [23] "  <body>"                                                                                                                                                                                                                                                                                                                                            
##  [24] "    <div class=\"container page\">"                                                                                                                                                                                                                                                                                                                  
##  [25] "      <div class=\"row\">"                                                                                                                                                                                                                                                                                                                           
##  [26] "        <div class=\"col-xs-12 col-sm-offset-1 col-sm-2 sidebar\" role=\"navigation\">"                                                                                                                                                                                                                                                              
##  [27] "<div class=\"row\">"                                                                                                                                                                                                                                                                                                                                 
##  [28] "<div class=\"col-xs-6 col-sm-12\">"                                                                                                                                                                                                                                                                                                                  
##  [29] "<p><a href=\"/\"><img src=\"/Rlogo.png\" width=\"100\" height=\"78\" alt = \"R\" /></a></p>"                                                                                                                                                                                                                                                         
##  [30] "<p><small><a href=\"/\">[Home]</a></small></p>"                                                                                                                                                                                                                                                                                                      
##  [31] "<h2 id=\"download\">Download</h2>"                                                                                                                                                                                                                                                                                                                   
##  [32] "<p><a href=\"http://cran.r-project.org/mirrors.html\">CRAN</a></p>"                                                                                                                                                                                                                                                                                  
##  [33] "<h2 id=\"r-project\">R Project</h2>"                                                                                                                                                                                                                                                                                                                 
##  [34] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [35] "<li><a href=\"/about.html\">About R</a></li>"                                                                                                                                                                                                                                                                                                        
##  [36] "<li><a href=\"/logo/\">Logo</a></li>"                                                                                                                                                                                                                                                                                                                
##  [37] "<li><a href=\"/contributors.html\">Contributors</a></li>"                                                                                                                                                                                                                                                                                            
##  [38] "<li><a href=\"/news.html\">What’s New?</a></li>"                                                                                                                                                                                                                                                                                                     
##  [39] "<li><a href=\"/bugs.html\">Reporting Bugs</a></li>"                                                                                                                                                                                                                                                                                                  
##  [40] "<li><a href=\"/conferences/\">Conferences</a></li>"                                                                                                                                                                                                                                                                                                  
##  [41] "<li><a href=\"/search.html\">Search</a></li>"                                                                                                                                                                                                                                                                                                        
##  [42] "<li><a href=\"/mail.html\">Get Involved: Mailing Lists</a></li>"                                                                                                                                                                                                                                                                                     
##  [43] "<li><a href=\"http://developer.R-project.org\">Developer Pages</a></li>"                                                                                                                                                                                                                                                                             
##  [44] "<li><a href=\"https://developer.r-project.org/Blog/public/\">R Blog</a></li>"                                                                                                                                                                                                                                                                        
##  [45] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [46] "</div>"                                                                                                                                                                                                                                                                                                                                              
##  [47] "<div class=\"col-xs-6 col-sm-12\">"                                                                                                                                                                                                                                                                                                                  
##  [48] "<h2 id=\"r-foundation\">R Foundation</h2>"                                                                                                                                                                                                                                                                                                           
##  [49] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [50] "<li><a href=\"/foundation/\">Foundation</a></li>"                                                                                                                                                                                                                                                                                                    
##  [51] "<li><a href=\"/foundation/board.html\">Board</a></li>"                                                                                                                                                                                                                                                                                               
##  [52] "<li><a href=\"/foundation/members.html\">Members</a></li>"                                                                                                                                                                                                                                                                                           
##  [53] "<li><a href=\"/foundation/donors.html\">Donors</a></li>"                                                                                                                                                                                                                                                                                             
##  [54] "<li><a href=\"/foundation/donations.html\">Donate</a></li>"                                                                                                                                                                                                                                                                                          
##  [55] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [56] "<h2 id=\"help-with-r\">Help With R</h2>"                                                                                                                                                                                                                                                                                                             
##  [57] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [58] "<li><a href=\"/help.html\">Getting Help</a></li>"                                                                                                                                                                                                                                                                                                    
##  [59] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [60] "<h2 id=\"documentation\">Documentation</h2>"                                                                                                                                                                                                                                                                                                         
##  [61] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [62] "<li><a href=\"http://cran.r-project.org/manuals.html\">Manuals</a></li>"                                                                                                                                                                                                                                                                             
##  [63] "<li><a href=\"http://cran.r-project.org/faqs.html\">FAQs</a></li>"                                                                                                                                                                                                                                                                                   
##  [64] "<li><a href=\"http://journal.r-project.org\">The R Journal</a></li>"                                                                                                                                                                                                                                                                                 
##  [65] "<li><a href=\"/doc/bib/R-books.html\">Books</a></li>"                                                                                                                                                                                                                                                                                                
##  [66] "<li><a href=\"/certification.html\">Certification</a></li>"                                                                                                                                                                                                                                                                                          
##  [67] "<li><a href=\"/other-docs.html\">Other</a></li>"                                                                                                                                                                                                                                                                                                     
##  [68] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [69] "<h2 id=\"links\">Links</h2>"                                                                                                                                                                                                                                                                                                                         
##  [70] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [71] "<li><a href=\"http://www.bioconductor.org\">Bioconductor</a></li>"                                                                                                                                                                                                                                                                                   
##  [72] "<li><a href=\"/other-projects.html\">Related Projects</a></li>"                                                                                                                                                                                                                                                                                      
##  [73] "<li><a href=\"/gsoc.html\">GSoC</a></li>"                                                                                                                                                                                                                                                                                                            
##  [74] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [75] "</div>"                                                                                                                                                                                                                                                                                                                                              
##  [76] "</div>"                                                                                                                                                                                                                                                                                                                                              
##  [77] "        </div>"                                                                                                                                                                                                                                                                                                                                      
##  [78] "        <div class=\"col-xs-12 col-sm-7\">"                                                                                                                                                                                                                                                                                                          
##  [79] "        <h1>The R Project for Statistical Computing</h1>"                                                                                                                                                                                                                                                                                            
##  [80] "<h2 id=\"getting-started\">Getting Started</h2>"                                                                                                                                                                                                                                                                                                     
##  [81] "<p>R is a free software environment for statistical computing and graphics. It compiles and runs on a wide variety of UNIX platforms, Windows and MacOS. To <strong><a href=\"http://cran.r-project.org/mirrors.html\">download R</a></strong>, please choose your preferred <a href=\"http://cran.r-project.org/mirrors.html\">CRAN mirror</a>.</p>"
##  [82] "<p>If you have questions about R like how to download and install the software, or what the license terms are, please read our <a href=\"http://cran.R-project.org/faqs.html\">answers to frequently asked questions</a> before you send an email.</p>"                                                                                              
##  [83] "<h2 id=\"news\">News</h2>"                                                                                                                                                                                                                                                                                                                           
##  [84] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [85] "<li><p><a href=\"https://cran.r-project.org/src/base/R-3\"><strong>R version 3.6.1 (Action of the Toes)</strong></a> has been released on 2019-07-05.</p></li>"                                                                                                                                                                                      
##  [86] "<li><p>useR! 2020 will take place in St. Louis, Missouri, USA.</p></li>"                                                                                                                                                                                                                                                                             
##  [87] "<li><p><a href=\"https://cran.r-project.org/src/base/R-3\"><strong>R version 3.5.3 (Great Truth)</strong></a> has been released on 2019-03-11.</p></li>"                                                                                                                                                                                             
##  [88] "<li><p>The R Foundation Conference Committee has released a <a href=\"https://www.r-project.org/useR-2020_call.html\">call for proposals</a> to host useR! 2020 in North America.</p></li>"                                                                                                                                                          
##  [89] "<li><p>You can now support the R Foundation with a renewable subscription as a <a href=\"https://www.r-project.org/foundation/donations.html\">supporting member</a></p></li>"                                                                                                                                                                       
##  [90] "<li><p>The R Foundation has been awarded the Personality/Organization of the year 2018 award by the professional association of German market and social researchers.</p></li>"                                                                                                                                                                      
##  [91] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [92] "<h2 id=\"news-via-twitter\">News via Twitter</h2>"                                                                                                                                                                                                                                                                                                   
##  [93] "<a class=\"twitter-timeline\""                                                                                                                                                                                                                                                                                                                       
##  [94] " href=\"https://twitter.com/_R_Foundation?ref_src=twsrc%5Etfw\""                                                                                                                                                                                                                                                                                     
##  [95] " data-width=\"400\""                                                                                                                                                                                                                                                                                                                                 
##  [96] " data-show-replies=\"false\""                                                                                                                                                                                                                                                                                                                        
##  [97] " data-chrome=\"noheader,nofooter,noborders\""                                                                                                                                                                                                                                                                                                        
##  [98] " data-dnt=\"true\""                                                                                                                                                                                                                                                                                                                                  
##  [99] " data-tweet-limit=\"3\">News from the R Foundation</a>"                                                                                                                                                                                                                                                                                              
## [100] "<script async"                                                                                                                                                                                                                                                                                                                                       
## [101] " src=\"https://platform.twitter.com/widgets.js\""                                                                                                                                                                                                                                                                                                    
## [102] " charset=\"utf-8\"></script>"                                                                                                                                                                                                                                                                                                                        
## [103] "<!--- (Boilerplate for release run-in)"                                                                                                                                                                                                                                                                                                              
## [104] "-   [**R version 3.1.3 (Smooth Sidewalk) prerelease versions**](http://cran.r-project.org/src/base-prerelease) will appear starting February 28. Final release is scheduled for 2015-03-09."                                                                                                                                                         
## [105] "-->"                                                                                                                                                                                                                                                                                                                                                 
## [106] "        </div>"                                                                                                                                                                                                                                                                                                                                      
## [107] "      </div>"                                                                                                                                                                                                                                                                                                                                        
## [108] "      <div class=\"raw footer\">"                                                                                                                                                                                                                                                                                                                    
## [109] "        &copy; The R Foundation. For queries about this web site, please contact"                                                                                                                                                                                                                                                                    
## [110] "\t<script type='text/javascript'>"                                                                                                                                                                                                                                                                                                                   
## [111] "<!--"                                                                                                                                                                                                                                                                                                                                                
## [112] "var s=\"=b!isfg>#nbjmup;xfcnbtufsAs.qspkfdu/psh#?uif!xfcnbtufs=0b?\";"                                                                                                                                                                                                                                                                               
## [113] "m=\"\"; for (i=0; i<s.length; i++) {if(s.charCodeAt(i) == 28){m+= '&';} else if (s.charCodeAt(i) == 23) {m+= '!';} else {m+=String.fromCharCode(s.charCodeAt(i)-1);}}document.write(m);//-->"                                                                                                                                                        
## [114] "\t</script>;"                                                                                                                                                                                                                                                                                                                                        
## [115] "        for queries about R itself, please consult the "                                                                                                                                                                                                                                                                                             
## [116] "        <a href=\"help.html\">Getting Help</a> section."                                                                                                                                                                                                                                                                                             
## [117] "      </div>"                                                                                                                                                                                                                                                                                                                                        
## [118] "    </div>"                                                                                                                                                                                                                                                                                                                                          
## [119] "    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->"                                                                                                                                                                                                                                                                                  
## [120] "    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js\"></script>"                                                                                                                                                                                                                                                     
## [121] "    <!-- Include all compiled plugins (below), or include individual files as needed -->"                                                                                                                                                                                                                                                            
## [122] "    <script src=\"/js/bootstrap.min.js\"></script>"                                                                                                                                                                                                                                                                                                  
## [123] "  </body>"                                                                                                                                                                                                                                                                                                                                           
## [124] "</html>"
# Y ahora usándolo
map(urls, safely(readLines))
## $example
## $example$result
##  [1] "<!doctype html>"                                                                                      
##  [2] "<html>"                                                                                               
##  [3] "<head>"                                                                                               
##  [4] "    <title>Example Domain</title>"                                                                    
##  [5] ""                                                                                                     
##  [6] "    <meta charset=\"utf-8\" />"                                                                       
##  [7] "    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />"                        
##  [8] "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />"                       
##  [9] "    <style type=\"text/css\">"                                                                        
## [10] "    body {"                                                                                           
## [11] "        background-color: #f0f0f2;"                                                                   
## [12] "        margin: 0;"                                                                                   
## [13] "        padding: 0;"                                                                                  
## [14] "        font-family: \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;"                
## [15] "        "                                                                                             
## [16] "    }"                                                                                                
## [17] "    div {"                                                                                            
## [18] "        width: 600px;"                                                                                
## [19] "        margin: 5em auto;"                                                                            
## [20] "        padding: 50px;"                                                                               
## [21] "        background-color: #fff;"                                                                      
## [22] "        border-radius: 1em;"                                                                          
## [23] "    }"                                                                                                
## [24] "    a:link, a:visited {"                                                                              
## [25] "        color: #38488f;"                                                                              
## [26] "        text-decoration: none;"                                                                       
## [27] "    }"                                                                                                
## [28] "    @media (max-width: 700px) {"                                                                      
## [29] "        body {"                                                                                       
## [30] "            background-color: #fff;"                                                                  
## [31] "        }"                                                                                            
## [32] "        div {"                                                                                        
## [33] "            width: auto;"                                                                             
## [34] "            margin: 0 auto;"                                                                          
## [35] "            border-radius: 0;"                                                                        
## [36] "            padding: 1em;"                                                                            
## [37] "        }"                                                                                            
## [38] "    }"                                                                                                
## [39] "    </style>    "                                                                                     
## [40] "</head>"                                                                                              
## [41] ""                                                                                                     
## [42] "<body>"                                                                                               
## [43] "<div>"                                                                                                
## [44] "    <h1>Example Domain</h1>"                                                                          
## [45] "    <p>This domain is established to be used for illustrative examples in documents. You may use this"
## [46] "    domain in examples without prior coordination or asking for permission.</p>"                      
## [47] "    <p><a href=\"http://www.iana.org/domains/example\">More information...</a></p>"                   
## [48] "</div>"                                                                                               
## [49] "</body>"                                                                                              
## [50] "</html>"                                                                                              
## 
## $example$error
## NULL
## 
## 
## $rproj
## $rproj$result
##   [1] "<!DOCTYPE html>"                                                                                                                                                                                                                                                                                                                                     
##   [2] "<html lang=\"en\">"                                                                                                                                                                                                                                                                                                                                  
##   [3] "  <head>"                                                                                                                                                                                                                                                                                                                                            
##   [4] "    <meta charset=\"utf-8\">"                                                                                                                                                                                                                                                                                                                        
##   [5] "    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">"                                                                                                                                                                                                                                                                                       
##   [6] "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"                                                                                                                                                                                                                                                                        
##   [7] "    <title>R: The R Project for Statistical Computing</title>"                                                                                                                                                                                                                                                                                       
##   [8] ""                                                                                                                                                                                                                                                                                                                                                    
##   [9] "    <link rel=\"icon\" type=\"image/png\" href=\"/favicon-32x32.png\" sizes=\"32x32\" />"                                                                                                                                                                                                                                                            
##  [10] "    <link rel=\"icon\" type=\"image/png\" href=\"/favicon-16x16.png\" sizes=\"16x16\" />"                                                                                                                                                                                                                                                            
##  [11] ""                                                                                                                                                                                                                                                                                                                                                    
##  [12] "    <!-- Bootstrap -->"                                                                                                                                                                                                                                                                                                                              
##  [13] "    <link href=\"/css/bootstrap.min.css\" rel=\"stylesheet\">"                                                                                                                                                                                                                                                                                       
##  [14] "    <link href=\"/css/R.css\" rel=\"stylesheet\">"                                                                                                                                                                                                                                                                                                   
##  [15] ""                                                                                                                                                                                                                                                                                                                                                    
##  [16] "    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->"                                                                                                                                                                                                                                                          
##  [17] "    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->"                                                                                                                                                                                                                                                                      
##  [18] "    <!--[if lt IE 9]>"                                                                                                                                                                                                                                                                                                                               
##  [19] "      <script src=\"https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js\"></script>"                                                                                                                                                                                                                                                             
##  [20] "      <script src=\"https://oss.maxcdn.com/respond/1.4.2/respond.min.js\"></script>"                                                                                                                                                                                                                                                                 
##  [21] "    <![endif]-->"                                                                                                                                                                                                                                                                                                                                    
##  [22] "  </head>"                                                                                                                                                                                                                                                                                                                                           
##  [23] "  <body>"                                                                                                                                                                                                                                                                                                                                            
##  [24] "    <div class=\"container page\">"                                                                                                                                                                                                                                                                                                                  
##  [25] "      <div class=\"row\">"                                                                                                                                                                                                                                                                                                                           
##  [26] "        <div class=\"col-xs-12 col-sm-offset-1 col-sm-2 sidebar\" role=\"navigation\">"                                                                                                                                                                                                                                                              
##  [27] "<div class=\"row\">"                                                                                                                                                                                                                                                                                                                                 
##  [28] "<div class=\"col-xs-6 col-sm-12\">"                                                                                                                                                                                                                                                                                                                  
##  [29] "<p><a href=\"/\"><img src=\"/Rlogo.png\" width=\"100\" height=\"78\" alt = \"R\" /></a></p>"                                                                                                                                                                                                                                                         
##  [30] "<p><small><a href=\"/\">[Home]</a></small></p>"                                                                                                                                                                                                                                                                                                      
##  [31] "<h2 id=\"download\">Download</h2>"                                                                                                                                                                                                                                                                                                                   
##  [32] "<p><a href=\"http://cran.r-project.org/mirrors.html\">CRAN</a></p>"                                                                                                                                                                                                                                                                                  
##  [33] "<h2 id=\"r-project\">R Project</h2>"                                                                                                                                                                                                                                                                                                                 
##  [34] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [35] "<li><a href=\"/about.html\">About R</a></li>"                                                                                                                                                                                                                                                                                                        
##  [36] "<li><a href=\"/logo/\">Logo</a></li>"                                                                                                                                                                                                                                                                                                                
##  [37] "<li><a href=\"/contributors.html\">Contributors</a></li>"                                                                                                                                                                                                                                                                                            
##  [38] "<li><a href=\"/news.html\">What’s New?</a></li>"                                                                                                                                                                                                                                                                                                     
##  [39] "<li><a href=\"/bugs.html\">Reporting Bugs</a></li>"                                                                                                                                                                                                                                                                                                  
##  [40] "<li><a href=\"/conferences/\">Conferences</a></li>"                                                                                                                                                                                                                                                                                                  
##  [41] "<li><a href=\"/search.html\">Search</a></li>"                                                                                                                                                                                                                                                                                                        
##  [42] "<li><a href=\"/mail.html\">Get Involved: Mailing Lists</a></li>"                                                                                                                                                                                                                                                                                     
##  [43] "<li><a href=\"http://developer.R-project.org\">Developer Pages</a></li>"                                                                                                                                                                                                                                                                             
##  [44] "<li><a href=\"https://developer.r-project.org/Blog/public/\">R Blog</a></li>"                                                                                                                                                                                                                                                                        
##  [45] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [46] "</div>"                                                                                                                                                                                                                                                                                                                                              
##  [47] "<div class=\"col-xs-6 col-sm-12\">"                                                                                                                                                                                                                                                                                                                  
##  [48] "<h2 id=\"r-foundation\">R Foundation</h2>"                                                                                                                                                                                                                                                                                                           
##  [49] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [50] "<li><a href=\"/foundation/\">Foundation</a></li>"                                                                                                                                                                                                                                                                                                    
##  [51] "<li><a href=\"/foundation/board.html\">Board</a></li>"                                                                                                                                                                                                                                                                                               
##  [52] "<li><a href=\"/foundation/members.html\">Members</a></li>"                                                                                                                                                                                                                                                                                           
##  [53] "<li><a href=\"/foundation/donors.html\">Donors</a></li>"                                                                                                                                                                                                                                                                                             
##  [54] "<li><a href=\"/foundation/donations.html\">Donate</a></li>"                                                                                                                                                                                                                                                                                          
##  [55] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [56] "<h2 id=\"help-with-r\">Help With R</h2>"                                                                                                                                                                                                                                                                                                             
##  [57] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [58] "<li><a href=\"/help.html\">Getting Help</a></li>"                                                                                                                                                                                                                                                                                                    
##  [59] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [60] "<h2 id=\"documentation\">Documentation</h2>"                                                                                                                                                                                                                                                                                                         
##  [61] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [62] "<li><a href=\"http://cran.r-project.org/manuals.html\">Manuals</a></li>"                                                                                                                                                                                                                                                                             
##  [63] "<li><a href=\"http://cran.r-project.org/faqs.html\">FAQs</a></li>"                                                                                                                                                                                                                                                                                   
##  [64] "<li><a href=\"http://journal.r-project.org\">The R Journal</a></li>"                                                                                                                                                                                                                                                                                 
##  [65] "<li><a href=\"/doc/bib/R-books.html\">Books</a></li>"                                                                                                                                                                                                                                                                                                
##  [66] "<li><a href=\"/certification.html\">Certification</a></li>"                                                                                                                                                                                                                                                                                          
##  [67] "<li><a href=\"/other-docs.html\">Other</a></li>"                                                                                                                                                                                                                                                                                                     
##  [68] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [69] "<h2 id=\"links\">Links</h2>"                                                                                                                                                                                                                                                                                                                         
##  [70] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [71] "<li><a href=\"http://www.bioconductor.org\">Bioconductor</a></li>"                                                                                                                                                                                                                                                                                   
##  [72] "<li><a href=\"/other-projects.html\">Related Projects</a></li>"                                                                                                                                                                                                                                                                                      
##  [73] "<li><a href=\"/gsoc.html\">GSoC</a></li>"                                                                                                                                                                                                                                                                                                            
##  [74] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [75] "</div>"                                                                                                                                                                                                                                                                                                                                              
##  [76] "</div>"                                                                                                                                                                                                                                                                                                                                              
##  [77] "        </div>"                                                                                                                                                                                                                                                                                                                                      
##  [78] "        <div class=\"col-xs-12 col-sm-7\">"                                                                                                                                                                                                                                                                                                          
##  [79] "        <h1>The R Project for Statistical Computing</h1>"                                                                                                                                                                                                                                                                                            
##  [80] "<h2 id=\"getting-started\">Getting Started</h2>"                                                                                                                                                                                                                                                                                                     
##  [81] "<p>R is a free software environment for statistical computing and graphics. It compiles and runs on a wide variety of UNIX platforms, Windows and MacOS. To <strong><a href=\"http://cran.r-project.org/mirrors.html\">download R</a></strong>, please choose your preferred <a href=\"http://cran.r-project.org/mirrors.html\">CRAN mirror</a>.</p>"
##  [82] "<p>If you have questions about R like how to download and install the software, or what the license terms are, please read our <a href=\"http://cran.R-project.org/faqs.html\">answers to frequently asked questions</a> before you send an email.</p>"                                                                                              
##  [83] "<h2 id=\"news\">News</h2>"                                                                                                                                                                                                                                                                                                                           
##  [84] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [85] "<li><p><a href=\"https://cran.r-project.org/src/base/R-3\"><strong>R version 3.6.1 (Action of the Toes)</strong></a> has been released on 2019-07-05.</p></li>"                                                                                                                                                                                      
##  [86] "<li><p>useR! 2020 will take place in St. Louis, Missouri, USA.</p></li>"                                                                                                                                                                                                                                                                             
##  [87] "<li><p><a href=\"https://cran.r-project.org/src/base/R-3\"><strong>R version 3.5.3 (Great Truth)</strong></a> has been released on 2019-03-11.</p></li>"                                                                                                                                                                                             
##  [88] "<li><p>The R Foundation Conference Committee has released a <a href=\"https://www.r-project.org/useR-2020_call.html\">call for proposals</a> to host useR! 2020 in North America.</p></li>"                                                                                                                                                          
##  [89] "<li><p>You can now support the R Foundation with a renewable subscription as a <a href=\"https://www.r-project.org/foundation/donations.html\">supporting member</a></p></li>"                                                                                                                                                                       
##  [90] "<li><p>The R Foundation has been awarded the Personality/Organization of the year 2018 award by the professional association of German market and social researchers.</p></li>"                                                                                                                                                                      
##  [91] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [92] "<h2 id=\"news-via-twitter\">News via Twitter</h2>"                                                                                                                                                                                                                                                                                                   
##  [93] "<a class=\"twitter-timeline\""                                                                                                                                                                                                                                                                                                                       
##  [94] " href=\"https://twitter.com/_R_Foundation?ref_src=twsrc%5Etfw\""                                                                                                                                                                                                                                                                                     
##  [95] " data-width=\"400\""                                                                                                                                                                                                                                                                                                                                 
##  [96] " data-show-replies=\"false\""                                                                                                                                                                                                                                                                                                                        
##  [97] " data-chrome=\"noheader,nofooter,noborders\""                                                                                                                                                                                                                                                                                                        
##  [98] " data-dnt=\"true\""                                                                                                                                                                                                                                                                                                                                  
##  [99] " data-tweet-limit=\"3\">News from the R Foundation</a>"                                                                                                                                                                                                                                                                                              
## [100] "<script async"                                                                                                                                                                                                                                                                                                                                       
## [101] " src=\"https://platform.twitter.com/widgets.js\""                                                                                                                                                                                                                                                                                                    
## [102] " charset=\"utf-8\"></script>"                                                                                                                                                                                                                                                                                                                        
## [103] "<!--- (Boilerplate for release run-in)"                                                                                                                                                                                                                                                                                                              
## [104] "-   [**R version 3.1.3 (Smooth Sidewalk) prerelease versions**](http://cran.r-project.org/src/base-prerelease) will appear starting February 28. Final release is scheduled for 2015-03-09."                                                                                                                                                         
## [105] "-->"                                                                                                                                                                                                                                                                                                                                                 
## [106] "        </div>"                                                                                                                                                                                                                                                                                                                                      
## [107] "      </div>"                                                                                                                                                                                                                                                                                                                                        
## [108] "      <div class=\"raw footer\">"                                                                                                                                                                                                                                                                                                                    
## [109] "        &copy; The R Foundation. For queries about this web site, please contact"                                                                                                                                                                                                                                                                    
## [110] "\t<script type='text/javascript'>"                                                                                                                                                                                                                                                                                                                   
## [111] "<!--"                                                                                                                                                                                                                                                                                                                                                
## [112] "var s=\"=b!isfg>#nbjmup;xfcnbtufsAs.qspkfdu/psh#?uif!xfcnbtufs=0b?\";"                                                                                                                                                                                                                                                                               
## [113] "m=\"\"; for (i=0; i<s.length; i++) {if(s.charCodeAt(i) == 28){m+= '&';} else if (s.charCodeAt(i) == 23) {m+= '!';} else {m+=String.fromCharCode(s.charCodeAt(i)-1);}}document.write(m);//-->"                                                                                                                                                        
## [114] "\t</script>;"                                                                                                                                                                                                                                                                                                                                        
## [115] "        for queries about R itself, please consult the "                                                                                                                                                                                                                                                                                             
## [116] "        <a href=\"help.html\">Getting Help</a> section."                                                                                                                                                                                                                                                                                             
## [117] "      </div>"                                                                                                                                                                                                                                                                                                                                        
## [118] "    </div>"                                                                                                                                                                                                                                                                                                                                          
## [119] "    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->"                                                                                                                                                                                                                                                                                  
## [120] "    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js\"></script>"                                                                                                                                                                                                                                                     
## [121] "    <!-- Include all compiled plugins (below), or include individual files as needed -->"                                                                                                                                                                                                                                                            
## [122] "    <script src=\"/js/bootstrap.min.js\"></script>"                                                                                                                                                                                                                                                                                                  
## [123] "  </body>"                                                                                                                                                                                                                                                                                                                                           
## [124] "</html>"                                                                                                                                                                                                                                                                                                                                             
## 
## $rproj$error
## NULL

Working with safe output

We now have output that contains the HTML for each of the two URLs on which readLines() was successful and the error for the other. But the output isn’t that easy to work with, since the results and errors are buried in the inner-most level of the list.

purrr provides a function transpose() that reshapes a list so the inner-most level becomes the outer-most level. In otherwords, it turns a list-of-lists “inside-out”. Consider the following list:

nested_list <- list( x1 = list(a = 1, b = 2), x2 = list(a = 3, b = 4) )

If I need to extract the a element in x1, I could do nested_list[[“x1”]][[“a”]]. However, if I transpose the list first, the order of subsetting reverses. That is, to extract the same element I could also do transpose(nested_list)[[“a”]][[“x1”]].

This is really handy for safe output, since we can grab all the results or all the errors really easily.

# Define safe_readLines() and html
safe_readLines <- safely(readLines)
html <- map(urls, safe_readLines)

# Examine the structure of transpose(html)
str(transpose(html))
## List of 2
##  $ result:List of 2
##   ..$ example: chr [1:50] "<!doctype html>" "<html>" "<head>" "    <title>Example Domain</title>" ...
##   ..$ rproj  : chr [1:124] "<!DOCTYPE html>" "<html lang=\"en\">" "  <head>" "    <meta charset=\"utf-8\">" ...
##  $ error :List of 2
##   ..$ example: NULL
##   ..$ rproj  : NULL
# Extract the results: res
res <- transpose(html)[["result"]]

# Extract the errors: errs
errs <- transpose(html)[["error"]]
# Initialize some objects
safe_readLines <- safely(readLines)
html <- map(urls, safe_readLines)
res <- transpose(html)[["result"]]
errs <- transpose(html)[["error"]]

# Create a logical vector is_ok
is_ok <- map_lgl(errs, is_null)

# Extract the successful results
res[is_ok]
## $example
##  [1] "<!doctype html>"                                                                                      
##  [2] "<html>"                                                                                               
##  [3] "<head>"                                                                                               
##  [4] "    <title>Example Domain</title>"                                                                    
##  [5] ""                                                                                                     
##  [6] "    <meta charset=\"utf-8\" />"                                                                       
##  [7] "    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />"                        
##  [8] "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />"                       
##  [9] "    <style type=\"text/css\">"                                                                        
## [10] "    body {"                                                                                           
## [11] "        background-color: #f0f0f2;"                                                                   
## [12] "        margin: 0;"                                                                                   
## [13] "        padding: 0;"                                                                                  
## [14] "        font-family: \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;"                
## [15] "        "                                                                                             
## [16] "    }"                                                                                                
## [17] "    div {"                                                                                            
## [18] "        width: 600px;"                                                                                
## [19] "        margin: 5em auto;"                                                                            
## [20] "        padding: 50px;"                                                                               
## [21] "        background-color: #fff;"                                                                      
## [22] "        border-radius: 1em;"                                                                          
## [23] "    }"                                                                                                
## [24] "    a:link, a:visited {"                                                                              
## [25] "        color: #38488f;"                                                                              
## [26] "        text-decoration: none;"                                                                       
## [27] "    }"                                                                                                
## [28] "    @media (max-width: 700px) {"                                                                      
## [29] "        body {"                                                                                       
## [30] "            background-color: #fff;"                                                                  
## [31] "        }"                                                                                            
## [32] "        div {"                                                                                        
## [33] "            width: auto;"                                                                             
## [34] "            margin: 0 auto;"                                                                          
## [35] "            border-radius: 0;"                                                                        
## [36] "            padding: 1em;"                                                                            
## [37] "        }"                                                                                            
## [38] "    }"                                                                                                
## [39] "    </style>    "                                                                                     
## [40] "</head>"                                                                                              
## [41] ""                                                                                                     
## [42] "<body>"                                                                                               
## [43] "<div>"                                                                                                
## [44] "    <h1>Example Domain</h1>"                                                                          
## [45] "    <p>This domain is established to be used for illustrative examples in documents. You may use this"
## [46] "    domain in examples without prior coordination or asking for permission.</p>"                      
## [47] "    <p><a href=\"http://www.iana.org/domains/example\">More information...</a></p>"                   
## [48] "</div>"                                                                                               
## [49] "</body>"                                                                                              
## [50] "</html>"                                                                                              
## 
## $rproj
##   [1] "<!DOCTYPE html>"                                                                                                                                                                                                                                                                                                                                     
##   [2] "<html lang=\"en\">"                                                                                                                                                                                                                                                                                                                                  
##   [3] "  <head>"                                                                                                                                                                                                                                                                                                                                            
##   [4] "    <meta charset=\"utf-8\">"                                                                                                                                                                                                                                                                                                                        
##   [5] "    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">"                                                                                                                                                                                                                                                                                       
##   [6] "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"                                                                                                                                                                                                                                                                        
##   [7] "    <title>R: The R Project for Statistical Computing</title>"                                                                                                                                                                                                                                                                                       
##   [8] ""                                                                                                                                                                                                                                                                                                                                                    
##   [9] "    <link rel=\"icon\" type=\"image/png\" href=\"/favicon-32x32.png\" sizes=\"32x32\" />"                                                                                                                                                                                                                                                            
##  [10] "    <link rel=\"icon\" type=\"image/png\" href=\"/favicon-16x16.png\" sizes=\"16x16\" />"                                                                                                                                                                                                                                                            
##  [11] ""                                                                                                                                                                                                                                                                                                                                                    
##  [12] "    <!-- Bootstrap -->"                                                                                                                                                                                                                                                                                                                              
##  [13] "    <link href=\"/css/bootstrap.min.css\" rel=\"stylesheet\">"                                                                                                                                                                                                                                                                                       
##  [14] "    <link href=\"/css/R.css\" rel=\"stylesheet\">"                                                                                                                                                                                                                                                                                                   
##  [15] ""                                                                                                                                                                                                                                                                                                                                                    
##  [16] "    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->"                                                                                                                                                                                                                                                          
##  [17] "    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->"                                                                                                                                                                                                                                                                      
##  [18] "    <!--[if lt IE 9]>"                                                                                                                                                                                                                                                                                                                               
##  [19] "      <script src=\"https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js\"></script>"                                                                                                                                                                                                                                                             
##  [20] "      <script src=\"https://oss.maxcdn.com/respond/1.4.2/respond.min.js\"></script>"                                                                                                                                                                                                                                                                 
##  [21] "    <![endif]-->"                                                                                                                                                                                                                                                                                                                                    
##  [22] "  </head>"                                                                                                                                                                                                                                                                                                                                           
##  [23] "  <body>"                                                                                                                                                                                                                                                                                                                                            
##  [24] "    <div class=\"container page\">"                                                                                                                                                                                                                                                                                                                  
##  [25] "      <div class=\"row\">"                                                                                                                                                                                                                                                                                                                           
##  [26] "        <div class=\"col-xs-12 col-sm-offset-1 col-sm-2 sidebar\" role=\"navigation\">"                                                                                                                                                                                                                                                              
##  [27] "<div class=\"row\">"                                                                                                                                                                                                                                                                                                                                 
##  [28] "<div class=\"col-xs-6 col-sm-12\">"                                                                                                                                                                                                                                                                                                                  
##  [29] "<p><a href=\"/\"><img src=\"/Rlogo.png\" width=\"100\" height=\"78\" alt = \"R\" /></a></p>"                                                                                                                                                                                                                                                         
##  [30] "<p><small><a href=\"/\">[Home]</a></small></p>"                                                                                                                                                                                                                                                                                                      
##  [31] "<h2 id=\"download\">Download</h2>"                                                                                                                                                                                                                                                                                                                   
##  [32] "<p><a href=\"http://cran.r-project.org/mirrors.html\">CRAN</a></p>"                                                                                                                                                                                                                                                                                  
##  [33] "<h2 id=\"r-project\">R Project</h2>"                                                                                                                                                                                                                                                                                                                 
##  [34] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [35] "<li><a href=\"/about.html\">About R</a></li>"                                                                                                                                                                                                                                                                                                        
##  [36] "<li><a href=\"/logo/\">Logo</a></li>"                                                                                                                                                                                                                                                                                                                
##  [37] "<li><a href=\"/contributors.html\">Contributors</a></li>"                                                                                                                                                                                                                                                                                            
##  [38] "<li><a href=\"/news.html\">What’s New?</a></li>"                                                                                                                                                                                                                                                                                                     
##  [39] "<li><a href=\"/bugs.html\">Reporting Bugs</a></li>"                                                                                                                                                                                                                                                                                                  
##  [40] "<li><a href=\"/conferences/\">Conferences</a></li>"                                                                                                                                                                                                                                                                                                  
##  [41] "<li><a href=\"/search.html\">Search</a></li>"                                                                                                                                                                                                                                                                                                        
##  [42] "<li><a href=\"/mail.html\">Get Involved: Mailing Lists</a></li>"                                                                                                                                                                                                                                                                                     
##  [43] "<li><a href=\"http://developer.R-project.org\">Developer Pages</a></li>"                                                                                                                                                                                                                                                                             
##  [44] "<li><a href=\"https://developer.r-project.org/Blog/public/\">R Blog</a></li>"                                                                                                                                                                                                                                                                        
##  [45] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [46] "</div>"                                                                                                                                                                                                                                                                                                                                              
##  [47] "<div class=\"col-xs-6 col-sm-12\">"                                                                                                                                                                                                                                                                                                                  
##  [48] "<h2 id=\"r-foundation\">R Foundation</h2>"                                                                                                                                                                                                                                                                                                           
##  [49] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [50] "<li><a href=\"/foundation/\">Foundation</a></li>"                                                                                                                                                                                                                                                                                                    
##  [51] "<li><a href=\"/foundation/board.html\">Board</a></li>"                                                                                                                                                                                                                                                                                               
##  [52] "<li><a href=\"/foundation/members.html\">Members</a></li>"                                                                                                                                                                                                                                                                                           
##  [53] "<li><a href=\"/foundation/donors.html\">Donors</a></li>"                                                                                                                                                                                                                                                                                             
##  [54] "<li><a href=\"/foundation/donations.html\">Donate</a></li>"                                                                                                                                                                                                                                                                                          
##  [55] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [56] "<h2 id=\"help-with-r\">Help With R</h2>"                                                                                                                                                                                                                                                                                                             
##  [57] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [58] "<li><a href=\"/help.html\">Getting Help</a></li>"                                                                                                                                                                                                                                                                                                    
##  [59] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [60] "<h2 id=\"documentation\">Documentation</h2>"                                                                                                                                                                                                                                                                                                         
##  [61] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [62] "<li><a href=\"http://cran.r-project.org/manuals.html\">Manuals</a></li>"                                                                                                                                                                                                                                                                             
##  [63] "<li><a href=\"http://cran.r-project.org/faqs.html\">FAQs</a></li>"                                                                                                                                                                                                                                                                                   
##  [64] "<li><a href=\"http://journal.r-project.org\">The R Journal</a></li>"                                                                                                                                                                                                                                                                                 
##  [65] "<li><a href=\"/doc/bib/R-books.html\">Books</a></li>"                                                                                                                                                                                                                                                                                                
##  [66] "<li><a href=\"/certification.html\">Certification</a></li>"                                                                                                                                                                                                                                                                                          
##  [67] "<li><a href=\"/other-docs.html\">Other</a></li>"                                                                                                                                                                                                                                                                                                     
##  [68] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [69] "<h2 id=\"links\">Links</h2>"                                                                                                                                                                                                                                                                                                                         
##  [70] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [71] "<li><a href=\"http://www.bioconductor.org\">Bioconductor</a></li>"                                                                                                                                                                                                                                                                                   
##  [72] "<li><a href=\"/other-projects.html\">Related Projects</a></li>"                                                                                                                                                                                                                                                                                      
##  [73] "<li><a href=\"/gsoc.html\">GSoC</a></li>"                                                                                                                                                                                                                                                                                                            
##  [74] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [75] "</div>"                                                                                                                                                                                                                                                                                                                                              
##  [76] "</div>"                                                                                                                                                                                                                                                                                                                                              
##  [77] "        </div>"                                                                                                                                                                                                                                                                                                                                      
##  [78] "        <div class=\"col-xs-12 col-sm-7\">"                                                                                                                                                                                                                                                                                                          
##  [79] "        <h1>The R Project for Statistical Computing</h1>"                                                                                                                                                                                                                                                                                            
##  [80] "<h2 id=\"getting-started\">Getting Started</h2>"                                                                                                                                                                                                                                                                                                     
##  [81] "<p>R is a free software environment for statistical computing and graphics. It compiles and runs on a wide variety of UNIX platforms, Windows and MacOS. To <strong><a href=\"http://cran.r-project.org/mirrors.html\">download R</a></strong>, please choose your preferred <a href=\"http://cran.r-project.org/mirrors.html\">CRAN mirror</a>.</p>"
##  [82] "<p>If you have questions about R like how to download and install the software, or what the license terms are, please read our <a href=\"http://cran.R-project.org/faqs.html\">answers to frequently asked questions</a> before you send an email.</p>"                                                                                              
##  [83] "<h2 id=\"news\">News</h2>"                                                                                                                                                                                                                                                                                                                           
##  [84] "<ul>"                                                                                                                                                                                                                                                                                                                                                
##  [85] "<li><p><a href=\"https://cran.r-project.org/src/base/R-3\"><strong>R version 3.6.1 (Action of the Toes)</strong></a> has been released on 2019-07-05.</p></li>"                                                                                                                                                                                      
##  [86] "<li><p>useR! 2020 will take place in St. Louis, Missouri, USA.</p></li>"                                                                                                                                                                                                                                                                             
##  [87] "<li><p><a href=\"https://cran.r-project.org/src/base/R-3\"><strong>R version 3.5.3 (Great Truth)</strong></a> has been released on 2019-03-11.</p></li>"                                                                                                                                                                                             
##  [88] "<li><p>The R Foundation Conference Committee has released a <a href=\"https://www.r-project.org/useR-2020_call.html\">call for proposals</a> to host useR! 2020 in North America.</p></li>"                                                                                                                                                          
##  [89] "<li><p>You can now support the R Foundation with a renewable subscription as a <a href=\"https://www.r-project.org/foundation/donations.html\">supporting member</a></p></li>"                                                                                                                                                                       
##  [90] "<li><p>The R Foundation has been awarded the Personality/Organization of the year 2018 award by the professional association of German market and social researchers.</p></li>"                                                                                                                                                                      
##  [91] "</ul>"                                                                                                                                                                                                                                                                                                                                               
##  [92] "<h2 id=\"news-via-twitter\">News via Twitter</h2>"                                                                                                                                                                                                                                                                                                   
##  [93] "<a class=\"twitter-timeline\""                                                                                                                                                                                                                                                                                                                       
##  [94] " href=\"https://twitter.com/_R_Foundation?ref_src=twsrc%5Etfw\""                                                                                                                                                                                                                                                                                     
##  [95] " data-width=\"400\""                                                                                                                                                                                                                                                                                                                                 
##  [96] " data-show-replies=\"false\""                                                                                                                                                                                                                                                                                                                        
##  [97] " data-chrome=\"noheader,nofooter,noborders\""                                                                                                                                                                                                                                                                                                        
##  [98] " data-dnt=\"true\""                                                                                                                                                                                                                                                                                                                                  
##  [99] " data-tweet-limit=\"3\">News from the R Foundation</a>"                                                                                                                                                                                                                                                                                              
## [100] "<script async"                                                                                                                                                                                                                                                                                                                                       
## [101] " src=\"https://platform.twitter.com/widgets.js\""                                                                                                                                                                                                                                                                                                    
## [102] " charset=\"utf-8\"></script>"                                                                                                                                                                                                                                                                                                                        
## [103] "<!--- (Boilerplate for release run-in)"                                                                                                                                                                                                                                                                                                              
## [104] "-   [**R version 3.1.3 (Smooth Sidewalk) prerelease versions**](http://cran.r-project.org/src/base-prerelease) will appear starting February 28. Final release is scheduled for 2015-03-09."                                                                                                                                                         
## [105] "-->"                                                                                                                                                                                                                                                                                                                                                 
## [106] "        </div>"                                                                                                                                                                                                                                                                                                                                      
## [107] "      </div>"                                                                                                                                                                                                                                                                                                                                        
## [108] "      <div class=\"raw footer\">"                                                                                                                                                                                                                                                                                                                    
## [109] "        &copy; The R Foundation. For queries about this web site, please contact"                                                                                                                                                                                                                                                                    
## [110] "\t<script type='text/javascript'>"                                                                                                                                                                                                                                                                                                                   
## [111] "<!--"                                                                                                                                                                                                                                                                                                                                                
## [112] "var s=\"=b!isfg>#nbjmup;xfcnbtufsAs.qspkfdu/psh#?uif!xfcnbtufs=0b?\";"                                                                                                                                                                                                                                                                               
## [113] "m=\"\"; for (i=0; i<s.length; i++) {if(s.charCodeAt(i) == 28){m+= '&';} else if (s.charCodeAt(i) == 23) {m+= '!';} else {m+=String.fromCharCode(s.charCodeAt(i)-1);}}document.write(m);//-->"                                                                                                                                                        
## [114] "\t</script>;"                                                                                                                                                                                                                                                                                                                                        
## [115] "        for queries about R itself, please consult the "                                                                                                                                                                                                                                                                                             
## [116] "        <a href=\"help.html\">Getting Help</a> section."                                                                                                                                                                                                                                                                                             
## [117] "      </div>"                                                                                                                                                                                                                                                                                                                                        
## [118] "    </div>"                                                                                                                                                                                                                                                                                                                                          
## [119] "    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->"                                                                                                                                                                                                                                                                                  
## [120] "    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js\"></script>"                                                                                                                                                                                                                                                     
## [121] "    <!-- Include all compiled plugins (below), or include individual files as needed -->"                                                                                                                                                                                                                                                            
## [122] "    <script src=\"/js/bootstrap.min.js\"></script>"                                                                                                                                                                                                                                                                                                  
## [123] "  </body>"                                                                                                                                                                                                                                                                                                                                           
## [124] "</html>"
# Find the URLs that were unsuccessful
urls[!is_ok]
## named list()

9.4.2 Maps sobre múltiples argumentos

Hasta ahora solo hemos iterado sobre un argumento. Ahora vamos a ver cómo iterar sobre múltiples argumentos con purrr.

Vamos a probar obtener muestras de una distribución normal.

library(purrr)

# Estos son ejecutando la función tres veces de modo independiente
rnorm(5)
## [1] -0.3080544  0.6045249 -0.3630189 -0.4034467 -0.4691486
rnorm(10)
##  [1] 0.18390427 1.13916014 0.86357007 0.42855912 0.46231701 0.97774527
##  [7] 0.09465831 0.12231912 0.79979208 1.14189785
rnorm(20)
##  [1]  0.25846021  0.60644206 -1.47632417  0.82384009 -1.99583825
##  [6] -0.74662085  0.05427656 -2.91828805  0.24734605  1.05059184
## [11] -1.92372825  0.08926865  0.32433027 -1.29294163  0.98115554
## [16] -1.47408014 -1.72943681  0.32008952  0.88480279 -0.13390709
# Y esto es utilizando map
map(list(5,10,20), rnorm)
## [[1]]
## [1] -0.8392258 -0.2306805  1.4099276  1.3457212  0.3896939
## 
## [[2]]
##  [1]  1.07594531 -0.03588153  0.96721368 -0.89961872  0.88902077
##  [6] -0.15733598  1.00058716 -1.07161843  0.86996558  0.40930158
## 
## [[3]]
##  [1]  0.52891171  1.36600624  0.84085514  0.72513885  0.09135081
##  [6] -1.11031007  2.40747178  2.05735654  0.09588862 -0.37671551
## [11]  0.74845688 -0.85334003 -3.21601518  1.35158871  0.06731999
## [16]  0.37003186 -1.10823006 -0.91275881 -1.10728591 -0.44534060
# Esto es generando un objeto n con la lista
n <- list(5, 10, 20)
map(n, rnorm)
## [[1]]
## [1] -0.1214852  1.0972787 -1.9015353 -0.8013919  0.3116227
## 
## [[2]]
##  [1] -1.5225633834  0.0000701671  0.8175266168 -0.2618073332 -0.5027718996
##  [6]  0.4322310054  0.5725034823  0.1104641494  2.7946134306 -0.7486751156
## 
## [[3]]
##  [1] -0.4687707 -0.4011974 -0.9545961 -0.3562791 -1.2256388 -1.1405732
##  [7] -0.3976995 -1.7961497  0.1755996  0.2601756  1.5391485 -0.9094471
## [13]  0.5568678  1.5803258  0.5185855 -0.2277831  0.6726475 -1.0631787
## [19]  0.1798851  0.3598185

En el ejemplo anterior hemos vistó cómo generar con map() tres muestras de diferente tamaño (5, 10, 20) que sigan una distribución normal. Sin embargo, rnorm() tiene esta estructura:

rnorm(n, mean = 0, sd = 1)

Nuestros tamaños muestrales, por tanto, estarán ajustados a una media de 0 y una desviación estándar de 1.

¿Qué pasa si queremos obtener también muestras con otros valores en los argumentos, esto es, con medias? Pues usamos la función map2() que nos permite introducir 2 argumentos adaptados:

map2(list(5,10,20),  # estos son los valores del tamaño muestral
     list(1, 5, 10), # estos son los valores de la media
     rnorm)          # esta es la función a ejecutar
## [[1]]
## [1] 1.5275249 1.1849822 1.7730267 0.8068752 1.2311357
## 
## [[2]]
##  [1] 4.591325 6.652464 5.443264 5.385944 6.292128 3.642295 4.695947
##  [8] 5.523505 4.371770 4.036292
## 
## [[3]]
##  [1]  8.080350 10.376446  8.961787 11.032845  8.465496 10.558539  8.136332
##  [8]  9.145212  7.718543 10.274247  9.189790 10.362671  9.111709  8.871576
## [15] 10.650738 10.093677 11.027807 10.640904  9.748060  9.503447

Como podemos ver, la iteración se produce con los elementos que ocupan el mismo lugar. Es decir, para el tamaño muestral 5 se usará la media de 1, para el tamaño muestral 10 se usará la media 5, y así sucesivamente.

¿Pero qué pasa si queremos utilizar también valores diferentes de la desviación estándar, al mismo tiempo que los tamaños muestrales y las medias? Estos ya serían tres argumentos a iterar. En este caso, en vez de generar una función map3() o map4() (si tuviésemos 4 argumentos), purrr ofrece una función genérica para más de 2 argumentos llamada pmap(). Es siempre necesario, aunque no obligatorio, que nombremos el nombre de los argumentos para evitar posibles errores en el orden. Por ejemplo, en el ejemplo siguiente, si ponemos primero la lista de medias y luego de tamaños muestrales (sin haber escrito n o mean) puede inducirnos a error y que el resultado sea equivocado al confundir pmap() el orden de los argumentos.

pmap(list(n =    list(5,  10, 20),  # estos son los valores de los tamaños muestrales
          mean = list( 1,  5, 10),  # estos son los valores de las medias
          sd =   list(.1, .5, .1)), # estos son los valores de las desviaciones estándar
     rnorm)                         # esta es la función a ejecutar
## [[1]]
## [1] 1.2302370 1.1155769 0.9227283 1.1089161 0.9595616
## 
## [[2]]
##  [1] 5.442841 5.350673 4.456865 6.348118 4.438001 5.844349 5.461769
##  [8] 4.555694 5.621701 5.468902
## 
## [[3]]
##  [1]  9.944657 10.181299 10.126754 10.120369  9.872263  9.926548 10.008957
##  [8] 10.083628  9.977965  9.829862 10.036063  9.989368  9.944397 10.001261
## [15] 10.141612 10.006788 10.055023  9.941570  9.997541  9.891150
# De modo análogo
n <-  list(5, 10, 20)
mu <- list(1,  5, 10)
desv_est <- list(.1, 1, .1)
pmap(list(n = n, 
          mean = mu, 
          sd = desv_est), rnorm)
## [[1]]
## [1] 0.9812708 1.0725612 1.1176263 1.1375731 0.8865784
## 
## [[2]]
##  [1] 3.791333 6.973924 5.081112 3.813903 4.533106 3.954965 6.683963
##  [8] 5.631692 5.365416 3.542123
## 
## [[3]]
##  [1]  9.904214 10.053679 10.046346  9.838320 10.040186  9.931982 10.018883
##  [8]  9.851361 10.007683 10.025394  9.980394  9.950273 10.066840  9.873623
## [15] 10.058603 10.033125 10.063532 10.115606 10.045546 10.187074

En esta ocasión se ha generado una lista con un conjunto de listas en su interior, cada una correspondiente a un argumento. Nuevamente, la iteración se produce entre los elementos situados en la misma posición. Es decir, el primer tamaño muestral con la primera media y la primera desviación estándar.

Por último, podríamos estar interesados no solo en interar sobre argumentos, sino también entre funciones. Por ejemplo, podríamos estar interesados en simular datos que siguieran tres distribuciones diferentes (por ejemplo, normal, uniforme y exponencial).

Esto se consigue en purrr con la función invoke_function(). Situamos primero la lista de funciones y luego el argumento.

rnorm(5)
## [1] -0.8232573  0.6090189 -0.4948791  0.2168707  0.4298965
runif(5)
## [1] 0.8308857 0.2578018 0.6567410 0.1910752 0.7454931
rexp(5)
## [1] 0.2208079 1.8335695 0.5615927 0.4576027 0.6266006
invoke_map(list(rnorm, runif, rexp), n = 5)
## [[1]]
## [1]  0.6297835  1.9807977 -1.3816177  0.1358079  0.3125299
## 
## [[2]]
## [1] 0.8101661 0.7167252 0.2173353 0.4340038 0.9071136
## 
## [[3]]
## [1] 1.78773894 0.17621312 1.02272661 0.05493275 0.68075032

En casos más complejos, podríamos necesitar que las funciones cogieran diferentes argumentos, o que queramos utilizar diferentes valores para cada función. En este caso, tendremos que definirlos con listas, donde cada elemento especifica el argumento para la función correspondiente. Vamos a verlo simulando una distribución normal (10, 1), uniforme (0, 5) y exponencial (5).

funs <- list("rnorm", "runif", "rexp") # definimos lista de funciones

rnorm_params <- list(mean = 10) # argumentos de la función rnorm()
runif_params <- list(min = 0, max = 5) # argumentos de la función runif()
rexp_params  <- list(rate = 5) # argumentos de la función rexp()

# Unimos los tres anteriores en el mismo orden que hayamos escrito las funciones arriba
params <- list(rnorm_params, runif_params, rexp_params)

# Ejecutamos invoke_map, teniendo en cuenta que queremos un tamaño muestral de 5 en todas ellas
invoke_map(funs, params, n = 5)
## [[1]]
## [1]  9.728018  8.670243 10.309910 11.269264 11.789258
## 
## [[2]]
## [1] 1.971786 0.422146 1.730242 1.446328 4.252676
## 
## [[3]]
## [1] 0.006715418 0.154301396 0.213431851 0.007705019 0.283362056

En resumen:

  • map2() nos permite iterar sobre dos argumentos.
  • pmap() nos permite iterar sobre 2 ó más argumentos.
  • invoke_map() nos permite iterar sobre funciones y argumentos.
  • Como en map(), dependiendo de cómo queramos el resultado, podemos tener map2_dbl(), map2_lgl(), pmap_dbl(), etc.

9.4.3 Maps con efectos colaterales

Algunas funciones en R no son escritas por el valor que devuelven, sino por el efecto colateral que producen. En esta caso vamos a ver las funciones walk de purrr.

Un efecto colateral es cualquier evento que ocurra que no sea el valor final de la función. Por lo tanto, describe eventos que ocurren más allá del resultado de la función.

Por ejemplo, crear un gráfico, mostrar una tabla y guardar los datos se consideran como efectos colaterales. En purrr, la función walk() esté hecha para poder iterar sobre estos efectos colaterales. Su estructura es idéntica a map(). También tienen la función walk2() y pwalk().

# Define list of functions
f <- list(Normal = "rnorm", Uniform = "runif", Exp = "rexp")

# Define params
params <- list(
  Normal = list(mean = 10),
  Uniform = list(min = 0, max = 5),
  Exp = list(rate = 5)
)

# Assign the simulated samples to sims
sims <- invoke_map(f, params, n = 50)

# Use walk() to make a histogram of each element in sims
walk(sims, hist)

Aunque ahora queremos personalizar los breaks de los histogramas.

# Replace "Sturges" with reasonable breaks for each sample
breaks_list <- list(
  Normal = seq(6, 16, 0.5),
  Uniform = seq(0, 5, 0.25),
  Exp = seq(0, 1.5, 0.1)
)

# Use walk2() to make histograms with the right breaks
walk2(sims, breaks_list, hist)

Antes hemos marcado los breaks de un modo manual. ¿Y si lo codificamos para que sea un proceso automático?

In the previous exercise, we hard-coded the breaks, but that was a little lazy. Those breaks probably won’t be great if we change the parameters of our simulation.

A better idea would be to generate reasonable breaks based on the actual values in our simulated samples. This is a great chance to review our function writing skills and combine our own function with purrr.

Let’s start by writing our own function find_breaks(), which copies the default breaks in the ggplot2 package: break the range of the data in 30 bins.

How do we start? Simple, of course! Here’s a snippet of code that works for the first sample:

rng <- range(sims[[1]], na.rm = TRUE) seq(rng[1], rng[2], length.out = 30)

Your job in this exercise is to turn that snippet into a function.

# Turn this snippet into find_breaks()
find_breaks <- function(x) {
  rng <- range(x, na.rm = TRUE)
  seq(rng[1], rng[2], length.out = 30)
}

# Call find_breaks() on sims[[1]]
find_breaks(sims)
##  [1]  0.001875773  0.432249980  0.862624187  1.292998394  1.723372601
##  [6]  2.153746808  2.584121015  3.014495222  3.444869429  3.875243636
## [11]  4.305617843  4.735992050  5.166366257  5.596740464  6.027114671
## [16]  6.457488878  6.887863085  7.318237292  7.748611499  8.178985706
## [21]  8.609359913  9.039734120  9.470108327  9.900482534 10.330856741
## [26] 10.761230948 11.191605155 11.621979362 12.052353569 12.482727776

Now that we have find_breaks(), we can find nice breaks for all the samples using map(). Then, pass the result into walk2() to get nice (but custom breaks) for our samples.

# Use map() to iterate find_breaks() over sims: nice_breaks
nice_breaks <- map(sims, find_breaks)

# Use nice_breaks as the second argument to walk2()
walk2(sims, nice_breaks, hist)

Ugh! Nice breaks but those plots had UUUUGLY labels and titles. The x-axis labels are easy to fix if we don’t mind every plot having its x-axis labeled the same way. We can use the … argument to any of the map() or walk() functions to pass in further arguments to the function .f. In this case, we might decide we don’t want any labels on the x-axis, in which case we need to pass an empty string to the xlab argument of hist():

walk2(sims, nice_breaks, hist, xlab = "")

But, what about the titles? We don’t want them to be the same for each plot. How can we iterate over the arguments x, breaks and main? You guessed it, there is a pwalk() function that works just like pmap().

Let’s use pwalk() to tidy up these plots. Also, let’s increase our sample size to 1000.

# Increase sample size to 1000
sims <- invoke_map(funs, params, n = 1000)

# Compute nice_breaks (don't change this)
nice_breaks <- map(sims, find_breaks)

# Create a vector nice_titles
nice_titles <- c("Normal(10, 1)", "Uniform(0, 5)", "Exp(5)")

# Use pwalk() instead of walk2()
pwalk(list(breaks = nice_breaks,
           x = sims,
           xlab = "",
           main = nice_titles), 
      hist)

One of the nice things about the walk() functions is that they return the object you passed to them. This means they can easily be used in pipelines (a pipeline is just a short way of saying “a statement with lots of pipes”).

To illustrate, we’ll return to our first example of making histograms for each sample:

walk(sims, hist)

Take a look at what gets returned:

tmp <- walk(sims, hist)

str(tmp)
## List of 3
##  $ : num [1:1000] 10.26 9.77 10.92 11.84 9.93 ...
##  $ : num [1:1000] 3.6 0.139 4.275 2.717 3.309 ...
##  $ : num [1:1000] 0.00457 0.02227 0.28261 0.32364 0.25261 ...

It’s our original sims object. That means we can pipe the sims object along to other functions. For example, we might want some basic summary statistics on each sample as well as our histograms.

# Pipe this along to map(), using summary() as .f
sims %>%
  walk(hist) %>%
  map(summary)

## [[1]]
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   6.969   9.356  10.000  10.021  10.680  13.387 
## 
## [[2]]
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
## 0.006303 1.224157 2.433107 2.456780 3.683839 4.999083 
## 
## [[3]]
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## 0.00007 0.06400 0.15602 0.21340 0.29678 1.44030

9.5 Funciones robustas

Entre otras situaciones, para que una función sea robusta debe de lanzar un mensaje de error preciso cuando no se cumplan algunos de sus requisitos. Es decir, el error debe ser informativo.

Estos problemas y la necesidad de que sean robustas las funciones se debe al hecho de que R son dos cosas en una: por un lado es un entorno de análisis de datos y por otro es un entorno de programación.

Una evidencia, por ejemplo, de que una función no es robusta es cuando:

  • el resultado de su ejecución no da siempre un mismo tipo de elemento.
  • se produce una evalución no estandarizada.
  • existen argumentos escondidos.

Una función interesante para poder evaluar los errores es stopifnot().

x <- 1:10
stopifnot(is.character(x)) 
# Define troublesome x and y
x <- c(NA, NA, NA)
y <- c( 1, NA, NA, NA)

both_na <- function(x, y) {
  # Add stopifnot() to check length of x and y
  stopifnot(length(x) == length(y)) # paramos si no son iguales sus dimensiones
  sum(is.na(x) & is.na(y))
}

Ejecutando la función la función con los dos vectores anteriores nos saldría un error:

both_na(x, y)

An informative error is even better

Using stop() instead of stopifnot() allows you to specify a more informative error message. Recall the general pattern for using stop() is:

if (condition) { stop(“Error”, call. = FALSE) }

Writing good error messages is an important part of writing a good function! We recommend your error tells the user what should be true, not what is false. For example, here a good error would be “x and y must have the same length”, rather than the bad error “x and y don’t have the same length”.

Let’s use this pattern to write a better check for the length of x and y.

# Define troublesome x and y
x <- c(NA, NA, NA)
y <- c( 1, NA, NA, NA)

both_na <- function(x, y) {
  # Replace condition with logical
  if (length(x) != length(y)) {
    # Replace "Error" with better message
    stop("x and y must have the same length", call. = FALSE) # hemos personalizado el error
  }  
  
  sum(is.na(x) & is.na(y))
}

Side effects describe the things that happen when you run a function that alters the state of your R session. If foo() is a function with no side effects (a.k.a. pure), then when we run x <- foo(), the only change we expect is that the variable x now has a new value. No other variables in the global environment should be changed or created, no output should be printed, no plots displayed, no files saved, no options changed. We know exactly the changes to the state of the session just by reading the call to the function.

9.5.1 Unstables types

Una clase de funciones que pueden dar sorpresas son las que devuelven resultados de diversos tipos, por lo que no son estables. Normalmente su resultado final depende del tipo de dato del input. Y esto puede generar que tengamos dificultades a la hora de saber cuál es el error.

Por ejemplo, con df[1, ] seleccionamos la primera fila de df. Si df tienes 2 ó más columnas, el resultado será un dataframe. Pero si solo tiene una columna el resultado será 1 vector. Esto en un principio es fácil identificarlo. Pero el problema surge si el subsetting lo tenemos dentro de una función más compleja, donde no controlamos exactamente qué es df. Esto demuestra que [] no es consistente a la hora de ofrecer los mismos resultados. Y esto hay que tenerlo en cuenta.

En el caso concreto de [], hay un argumento que hace que sea consistente: drop = FALSE. Por ejemplo, df[1, , drop = FALSE]. De este modo todo sale como dataframe.

Por lo tanto, ¿qué hacemos? Primero escribir funciones que sean estables y uniformes, evitando incluir en ellas funciones inestables. Además sería interesante tener un vocabulario o diccionario de funciones estables. Todas las funciones de purrr son estables, por lo tanto es muy recomendable su uso. No así [ o sapply.

df <- data.frame(
  a = 1L,
  b = 1.5,
  y = Sys.time(),
  z = ordered(1)
)

A <- sapply(df[1:4], class) 
B <- sapply(df[3:4], class)

Vemos que A es una lista y B una matriz.

This unpredictable behaviour is a sign that you shouldn’t rely on sapply() inside your own functions.

So, what do you do? Use alternate functions that are type consistent! And you already know a whole set: the map() functions in purrr.

In this example, when we call class() on the columns of the data frame we are expecting character output, so our function of choice should be: map_chr():

# veamos el ejemplo con sapply()
A <- sapply(df[1:4], class) 
B <- sapply(df[3:4], class)
C <- sapply(df[1:2], class) 

# Demonstrate type inconsistency
str(A)
## List of 4
##  $ a: chr "integer"
##  $ b: chr "numeric"
##  $ y: chr [1:2] "POSIXct" "POSIXt"
##  $ z: chr [1:2] "ordered" "factor"
str(B)
##  chr [1:2, 1:2] "POSIXct" "POSIXt" "ordered" "factor"
##  - attr(*, "dimnames")=List of 2
##   ..$ : NULL
##   ..$ : chr [1:2] "y" "z"
str(C)
##  Named chr [1:2] "integer" "numeric"
##  - attr(*, "names")= chr [1:2] "a" "b"
# Hacemos lo mismo que con sapply pero usando map() to define X, Y and Z
X <- map(df[1:4], class)
Y <- map(df[3:4], class)
Z <- map(df[1:2], class) 

# Use str() to check type consistency
str(X)
## List of 4
##  $ a: chr "integer"
##  $ b: chr "numeric"
##  $ y: chr [1:2] "POSIXct" "POSIXt"
##  $ z: chr [1:2] "ordered" "factor"
str(Y)
## List of 2
##  $ y: chr [1:2] "POSIXct" "POSIXt"
##  $ z: chr [1:2] "ordered" "factor"
str(Z)
## List of 2
##  $ a: chr "integer"
##  $ b: chr "numeric"

9.5.2 Non-standard evaluation

Let’s take a look at a function that uses the non-standard evaluation (NSE) function filter() from the dplyr package:

big_x <- function(df, threshold) { dplyr::filter(df, x > threshold) }

This big_x() function attempts to return all rows in df where the x column exceeds a certain threshold. Let’s get a feel for how it might be used.

Now, let’s see how this function might fail. There are two instances in which the non-standard evaluation of filter() could cause surprising results:

The x column doesn't exist in df.
There is a threshold column in df.

Let’s illustrate these failures. In each case we’ll use big_x() in the same way as the previous exercise, so we should expect the same output. However, not only do we get unexpected outputs, there is no indication (i.e. error message) that lets us know something might have gone wrong.

http://rpubs.com/hadley/157957

big_x <- function(df, threshold) {
  # Write a check for x not being in df
  if (!"x" %in% colnames(df)) { 
    stop("df must contain variable called x", call. = FALSE)
  }
  
  # Write a check for threshold being in df
  if ("threshold" %in% colnames(df)) {
    stop("df must not contain variable called threshold", call. = FALSE)
  }
  
  dplyr::filter(df, x > threshold)
}

9.5.3 Hidden functions

A classic example of a hidden dependence is the stringsAsFactors argument to the read.csv() function (and a few other data frame functions.)

When you see the following code, you don’t know exactly what the result will be:

pools <- read.csv(“swimming_pools.csv”)

That’s because if the argument stringsAsFactors isn’t specified, it inherits its value from getOption(“stringsAsFactors”), a global option that a user may change.

Just to prove that this is the case, let’s illustrate the problem.

# This is the default behavior
options(stringsAsFactors = TRUE)

# Read in the swimming_pools.csv to pools
pools <- read.csv("Datos/swimming_pools.csv")

# Examine the structure of pools
str(pools)
## 'data.frame':    20 obs. of  4 variables:
##  $ Name     : Factor w/ 20 levels "Acacia Ridge Leisure Centre",..: 1 2 3 4 5 6 19 7 8 9 ...
##  $ Address  : Factor w/ 20 levels "1 Fairlead Crescent, Manly",..: 5 20 18 10 9 11 6 15 12 17 ...
##  $ Latitude : num  -27.6 -27.6 -27.6 -27.5 -27.4 ...
##  $ Longitude: num  153 153 153 153 153 ...
# Change the global stringsAsFactors option to FALSE
options(stringsAsFactors = FALSE)

# Read in the swimming_pools.csv to pools2
pools2 <- read.csv("Datos/swimming_pools.csv")

# Examine the structure of pools2
str(pools2)
## 'data.frame':    20 obs. of  4 variables:
##  $ Name     : chr  "Acacia Ridge Leisure Centre" "Bellbowrie Pool" "Carole Park" "Centenary Pool (inner City)" ...
##  $ Address  : chr  "1391 Beaudesert Road, Acacia Ridge" "Sugarwood Street, Bellbowrie" "Cnr Boundary Road and Waterford Road Wacol" "400 Gregory Terrace, Spring Hill" ...
##  $ Latitude : num  -27.6 -27.6 -27.6 -27.5 -27.4 ...
##  $ Longitude: num  153 153 153 153 153 ...

In general, you want to avoid having the return value of your own functions depend on any global options. That way, you and others can reason about your functions without needing to know the current state of the options.

It is, however, okay to have side effects of a function depend on global options. For example, the print() function uses getOption(“digits”) as the default for the digits argument. This gives users some control over how results are displayed, but doesn’t change the underlying computation.

Let’s take a look at an example function that uses a global default sensibly. The print.lm() function has the options digits with default max(3, getOption(“digits”) - 3).

# Start with this
options(digits = 8)

# Fit a regression model
fit <- lm(mpg ~ wt, data = mtcars)

# Look at the summary of the model
summary(fit)
## 
## Call:
## lm(formula = mpg ~ wt, data = mtcars)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -4.5431 -2.3647 -0.1252  1.4096  6.8727 
## 
## Coefficients:
##             Estimate Std. Error t value  Pr(>|t|)    
## (Intercept)  37.2851     1.8776  19.858 < 2.2e-16 ***
## wt           -5.3445     0.5591  -9.559 1.294e-10 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3.0459 on 30 degrees of freedom
## Multiple R-squared:  0.75283,    Adjusted R-squared:  0.74459 
## F-statistic: 91.375 on 1 and 30 DF,  p-value: 1.294e-10
# Set the global digits option to 2
options(digits = 2)

# Take another look at the summary
summary(fit)
## 
## Call:
## lm(formula = mpg ~ wt, data = mtcars)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -4.543 -2.365 -0.125  1.410  6.873 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   37.285      1.878   19.86  < 2e-16 ***
## wt            -5.344      0.559   -9.56  1.3e-10 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3 on 30 degrees of freedom
## Multiple R-squared:  0.753,  Adjusted R-squared:  0.745 
## F-statistic: 91.4 on 1 and 30 DF,  p-value: 1.29e-10