Argumentos formales de funciones en R.

En R los argumentos de las funciones se pueden indicar por su posición o por su nombre.

misdatos <- rnorm(100)
formals(sd)
sd(misdatos)
sd(x = misdatos)
sd(x = misdatos, na.rm = FALSE)
sd(na.rm = FALSE, x = misdatos)
sd(na.rm = FALSE, misdatos)

Se recomienda utilizar el nombre de los argumentos y conservar el orden.

Se puede mezclar el emparejamiento por posición y por nombre. Cuándo se empareja por nombre, se “saca” de la lista de argumentos y los demás argumentos siguen el orden en que están definidos.

formals(lm)
args(lm)

x <- rnorm(1000, mean = 50, sd = 10)
y <- 1 + 5 * x + rnorm(1000)

misdatos <- data.frame(x,y)

lm(data = misdatos, y ~ x,  model = FALSE,  1:100)
lm(y ~ x, misdatos, 1:100, model = FALSE)

Los argumentos de las funciones pueden ser parcialmente emparejadas, lo cuál es útil en un trabajo interactivo.

El orden de emparejamiento es:

Además de no definir un valor por omisión se puede establecer como un argumento de NULL.

f <- function(a, b = 1, c = 2, d = NULL) {
   
}

Entorno de variables en funciones

x <- 3
fNada1 <- function(a){
  x <- 1
  a + x
}

fNada1(6)
## [1] 7
fNada2 <- function(a){
  a + x
}

fNada2(6)
## [1] 9
f1 <- function(x1) {
  f2 <- function(x2) {
    f3 <- function(x3) {
      x1 + x2 + x3
    }
    f3(3)
  }
  f2(2)
}
f1(1)
f1(3)

Evaluación “perezosa”.

Los argumentos de una función se evalúan de manera perezosa, de forma que se evalúan si se necesitan.

f <- function(a, b){
  a ^ 2
}

f(2)

Debido a que esta función realmente no utiliza el argumento b, el llamado la función f(2) no produce ningún error, porque el 2 se empareja con la variable a.

f <- function(a, b){
  print(a)
  print(b)
}

f(45)

Note que se muestra el 45 antes que se muestre el error. Sólo se muestra el error cuando se evalúa print(b)

El argumento ...

El argumento ... indica un número variable de argumentos, que usualmente se pasan a otras funciones.

... se usa para extender otra función y no se quiere copiar la lista completa de los argumentos de la función.

miplot <- function(x, y, type = "l", ...){
  plot(x, y, type = type, ...)  
}

Las funciones genéricas usan ... para que los argumentos extras se pasen a los métodos. (POO).

mean
## function (x, ...) 
## UseMethod("mean")
## <bytecode: 0x564505d69e10>
## <environment: namespace:base>

El argumento ... es necesario cuando el número de argumentos que se pasan a una función no se sabe con anticipación.

args(paste)
## function (..., sep = " ", collapse = NULL, recycle0 = FALSE) 
## NULL
args(cat)
## function (..., file = "", sep = " ", fill = FALSE, labels = NULL, 
##     append = FALSE) 
## NULL

Todo argumento que aparezca depués de ... deberá ser nombrado explícitamente y no se puede emparejar parcialmente.

args(paste)
## function (..., sep = " ", collapse = NULL, recycle0 = FALSE) 
## NULL
paste("a", "b", sep = ":")

paste("a", "b", se = ":")

Entrega de resultados de funciones

fmala <- function(x, y) {
 z1 <- 2 * x + y
 z2 <- x + 2 * y
 z3 <- 2 * x + 2 * y
 z4 <- x / y
}
r1 <- fmala(8, 10)
r1
fcorrecta <- function(x, y) {
 z1 <- 2 * x + y
 z2 <- x + 2 * y
 z3 <- 2 * x + 2 * y
 z4 <- x / y
 return(c(z1, z2, z3, z4))
}

r1 <- fcorrecta(1, 2)
r1

Si se retorna elementos más complejos es convenviente devolverlo en forma de lista.

f2 <- function(x, y) {
  z1 <- x + y
  z2 <- x + 2 * y
  list(z1, z2) 
}

f2(2, 5)

f2(2, 5)[[2]]

f2(2, 5)$z1
f3 <- function(x, y) {
  z1 <- x + y
  z2 <- x + 2 * y
  list(result1=z1, result2=z2)
}

f3(2, 5)

f3(2, 5)[[2]]

f3(2, 5)$result2

Tipos de argumentos.

v1 <- c(2, 3, 5, 7)
v2 <- c(4, 0, 1, 9)
f3(v1, v2)

m1 <- matrix(c(1, 2, 3, 4,  5,  6), ncol = 2)

m2 <- matrix(c(2, 4, 6, 8, 10, 12), ncol = 2)

f3(m1, m2)

Validación de argumentos.

f4 <- function(a, b, c, d) {
  stopifnot(a >= 0, a <= 1, b > 1, c > 0)
  r1 <- c(qnorm(a), log(b - 1), sqrt(c))
  return(r1)
}

f4(2, 2, 0.5)

f4(0.1, 0.5, 0.5)

f4(0.1, 5, -2)

f4(0.1, 0.5, -1)

Devolución de valores de tipo function o como objetos

potencia <- function(exponente) {
  function(x) {
    x ^ exponente
  }
}

cuadrado <- potencia(2)
cuadrado(2)
## [1] 4
cuadrado(4)
## [1] 16
cubo <- potencia(3)
cubo(2)
## [1] 8
cubo(4)
## [1] 64

Programación vectorial y matricial en R.

apply()

Aplica la función sobre un la marginal de un arreglo o matriz.

(m <- matrix(c(1:10, 11:20), nrow = 10, ncol = 2))
##       [,1] [,2]
##  [1,]    1   11
##  [2,]    2   12
##  [3,]    3   13
##  [4,]    4   14
##  [5,]    5   15
##  [6,]    6   16
##  [7,]    7   17
##  [8,]    8   18
##  [9,]    9   19
## [10,]   10   20
apply(m, 1, mean)
##  [1]  6  7  8  9 10 11 12 13 14 15
apply(m, 2, mean)
## [1]  5.5 15.5
apply(m, 1:2, function(x) x/2)
##       [,1] [,2]
##  [1,]  0.5  5.5
##  [2,]  1.0  6.0
##  [3,]  1.5  6.5
##  [4,]  2.0  7.0
##  [5,]  2.5  7.5
##  [6,]  3.0  8.0
##  [7,]  3.5  8.5
##  [8,]  4.0  9.0
##  [9,]  4.5  9.5
## [10,]  5.0 10.0

by()

Aplica la función sobre una división de una base de datos (data.frame) por un factor.

head(iris)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa
by(iris[, 1:4], iris$Species, colMeans)
## iris$Species: setosa
## Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
##        5.006        3.428        1.462        0.246 
## ------------------------------------------------------------ 
## iris$Species: versicolor
## Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
##        5.936        2.770        4.260        1.326 
## ------------------------------------------------------------ 
## iris$Species: virginica
## Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
##        6.588        2.974        5.552        2.026

eapply()

Aplica la función sobre los valores de un entorno.

e <- new.env()

e$a <- 1:10
e$b <- 11:20

eapply(e, mean)
## $a
## [1] 5.5
## 
## $b
## [1] 15.5

lapply()

Aplica una función sobre una lista o un vector.

l <- list(a = 1:10, b = 11:20)
lapply(l, mean)
## $a
## [1] 5.5
## 
## $b
## [1] 15.5
lapply(l, sum)
## $a
## [1] 55
## 
## $b
## [1] 155

sapply()

Aplica una función sobre una lista o un vector y si el resultado se puede simplificar en un formato más simple, lo hace.

l <- list(a = 1:10, b = 11:20)
sapply(l, mean)
##    a    b 
##  5.5 15.5
sapply(l, sum)
##   a   b 
##  55 155

vapply()

Aplica la función sobre una lista y devuelve el resultado de acuerdo a un formato indicado.

l <- list(a = 1:10, b = 11:20)
lFivenum <- vapply(l, 
                   fivenum, 
                   c(Min. = 0, "1er Cuart." = 0, 
                     Mediana = 0, "3er Cuart." = 0, Max. = 0))
class(lFivenum)
## [1] "matrix" "array"
lFivenum
##               a    b
## Min.        1.0 11.0
## 1er Cuart.  3.0 13.0
## Mediana     5.5 15.5
## 3er Cuart.  8.0 18.0
## Max.       10.0 20.0

replicate()

Replica la ejecución de una función un número específico de veces.s

replicate(10, rnorm(10))
##             [,1]        [,2]       [,3]        [,4]        [,5]       [,6]
##  [1,]  1.8659164 -0.24537513 -0.5098014 -0.24659462  0.00682603  2.0447584
##  [2,]  0.7855889  1.66356474 -0.9089635 -1.85902290 -0.47019513  1.0888464
##  [3,]  0.1103070 -0.52018135 -0.8227062  1.05867432 -0.57432968  1.4456075
##  [4,]  1.3516512  1.31996323 -1.2657186  0.00830816  1.07424576 -1.3008750
##  [5,]  0.1209635  1.23121856 -0.1157160 -0.05175267  1.65834950  0.9591093
##  [6,]  0.8656688  0.10194391 -0.5676031  1.02557988 -0.36862522  1.8214667
##  [7,]  0.5692012 -0.01595891 -1.3313603  0.21788155 -1.79040944 -1.8165792
##  [8,]  1.8724959  1.77400823  0.1599065 -1.17580828 -0.55262027  0.2723686
##  [9,] -1.4007935 -0.38180254 -0.1809476 -0.50449303 -1.71427267 -0.5174339
## [10,] -0.2731352 -0.40946293  1.7524197 -1.30554822  0.65706993 -0.3744553
##              [,7]       [,8]        [,9]      [,10]
##  [1,]  0.34250198 -0.2272914 -0.59505863 -0.5710257
##  [2,]  0.53388299  0.2326855  0.06101959 -1.4799010
##  [3,] -1.08319869  0.4972705  0.27976583 -0.2939348
##  [4,]  1.16811816 -0.1388716 -0.71905269  0.3199842
##  [5,]  0.01021332 -0.6833887  1.02361879  0.6131758
##  [6,] -1.32706448 -1.9321334 -2.30469742 -1.2167757
##  [7,] -0.37347934 -1.1317951  0.30683247  0.9384648
##  [8,]  0.42355116 -0.3802032  0.66839541 -0.2109320
##  [9,]  1.72869895  0.6669180  0.05501028 -0.4842013
## [10,] -0.63311603  0.8898050  0.17229377 -0.4551334
replicate(8, mean(rexp(10)))
## [1] 0.8833140 0.9622826 0.9518881 0.3584341 1.0805961 1.1773161 1.3479517
## [8] 1.0597841

mapply()

Es la versión multivariada de lapply y sapply. Aplica la función a los elementos correspondientes de múltiples listas.

l1 <- list(a = c(1:10), b = c(11:20))
l2 <- list(c = c(21:30), d = c(31:40))

mapply(sum, l1$a, l1$b, l2$c, l2$d)
##  [1]  64  68  72  76  80  84  88  92  96 100
mapply(sum, l1, l2)
##   a   b 
## 310 510
l2 <- list(c = c(21:30), d = c(31:40), z = c(31:50))

mapply(sum, l1$a, l1$b, l2$c, l2$z)
##  [1]  64  68  72  76  80  84  88  92  96 100  74  78  82  86  90  94  98 102 106
## [20] 110

tapply()

Aplica la función sobre un vector, de acuerdo a una clasificación de la variable tipo factor.

tapply(iris$Petal.Length, iris$Species, mean)
##     setosa versicolor  virginica 
##      1.462      4.260      5.552

Recomendaciones