Capítulo 13 Funciones

En R no solo podemos usar las funciones predeterminadas que vienen ya cargadas, o las de los paquetes que instalamos, como sum() o mean(). Además podemos crear nuestras propias funciones para automatizar tareas que vayamos a repetir a lo largo de nuestro código.

¿Cómo crear nuestra propia función? Veamos su esquema básico. Para crear una función necesitamos

  • Un nombre, por ejemplo nombre_funcion (sin espacios ni caracteres extraños)
  • A dicho nombre le asignamos <- la palabra reservada function().
  • Dentro de function() definimos los argumentos de entrada que usará la función.
  • Dentro de {} incluiremos la órdenes.
  • Finalizaremos la función con return() indicando los argumentos de salida
# No ejecutar --> esquema conceptual
nombre_funcion <- function(argumento_1, argumento_2, ... ) {
  
  # Código que queramos ejecutar en la función
  código
  
  # Salida
  return(variable_salida)
}

En el esquema anterior

  • argumento_1, argumento_2, …: serán los argumentos de entrada, los argumentos que toma la función para ejecutar el código que tiene dentro
  • código: líneas de código que queramos que ejecute la función. IMPORTANTE: todas las variables que definamos dentro de la función son variables locales, solo existirán dentro de la función salvo que especifiquemos lo contrario.
  • return(variable_salida): dentro del comando return() se introducirán los argumentos de salida, que puede ser un número, un data.frame, un caracter, una gráfica, una matriz…

13.1 Primera función

Veamos un ejemplo muy simple de función para calcular el área de un rectángulo.

¿Qué se necesita para calcular el área? Dado que el área de un rectángulo se calcula como el producto de sus lados, necesitaremos precisamente eso, sus lados: esos serán los argumentos de entrada (lado_1 y lado_2). el valor a devolver será justo su área, calculada como lado_1 * lado_2.

  1. Nombre –> calcular_area
  2. Argumentos –> lado_1, lado_2
  3. Código –> area <- lado_1 * lado_2
  4. Salida –> return(area)
# Definición del nombre de función y argumentos de entrada
calcular_area <- function(lado_1, lado_2) {
  
  # Cuerpo de la función (lo que hace)
  area <- lado_1 * lado_2
  
  # Resultado (lo que devuelve)
  return(area)
  
}

También podemos hacer una definición directa, sin almacenar variables por el camino

# Definición del nombre de función y argumentos de entrada
calcular_area <- function(lado_1, lado_2) {

  # Resultado que devolvemos
  return(lado_1 * lado_2)
  
}

¿Cómo aplicar la función? Haciendo uso del nombre y los valores de los argumentos, usamos calcular_area() y le pasamos los dos argumentos de entrada.

# Aplicación de la función con los parámetros por defecto
calcular_area(5, 3) # área de un rectángulo 5 x 3 
## [1] 15
calcular_area(1, 5) # área de un rectángulo 1 x 5
## [1] 5
calcular_area(3, 3) # área de un rectángulo 3 x 3 
## [1] 9

Imagina ahora que nos damos cuenta que el 90% de las veces usamos dicha función para calcular el área de un cuadrado (es decir, solo necesitamos un argumento, un lado, ya que en un cuadrado lado_1 = lado_2). Para ello, R nos permite definir argumentos por defecto en la función (tomarán dicho valor salvo que le asignemos otro, como nos ha pasado con el argumento na.rm para operar con datos ausentes). ¿Por qué no asignar lado_2 = lado_1 por defecto, para ahorrar líneas de código y tiempo?

# Definición del nombre de función y argumentos de entrada
# por defecto lado_2 = lado_1
calcular_area <- function(lado_1, lado_2 = lado_1) {
  
  # Cuerpo de la función
  area <- lado_1 * lado_2
  
  # Resultado que devolvemos
  return(area)
  
}

Ahora, si no indicamos nada, por defecto el segundo lado será igual al primero (un cuadrado), y si se lo añadimos usará ambos.

calcular_area(lado_1 = 5) # cuadrado: si no indicamos nada, lado_2 = lado_1
## [1] 25
calcular_area(lado_1 = 5, lado_2 = 7) # rectángulo
## [1] 35

 

Compliquemos un poco la función y añadamos en la salida los valores de cada lado, etiquetados como lado_1 y lado_2, empaquetando la salida en una lista.

# Definición del nombre de función y argumentos de entrada
calcular_area <- function(lado_1, lado_2 = lado_1) {
  
  # Cuerpo de la función
  area <- lado_1 * lado_2
  
  # Resultado
  return(list("area" = area, "lado_1" = lado_1, "lado_2" = lado_2))
  
}

Veamos que nos devuelve ahora

salida <- calcular_area(5, 3)
salida
## $area
## [1] 15
## 
## $lado_1
## [1] 5
## 
## $lado_2
## [1] 3
salida["area"]
## $area
## [1] 15
salida["lado_1"]
## $lado_1
## [1] 5
salida["lado_2"]
## $lado_2
## [1] 3

Antes nos daba igual el orden de los argumentos pero ahora no, ya que en la salida incluimos lado_1 y lado_2. Es altamente recomendable hacer la llamada a la función indicando explícitamente los argumentos argumento_1 = valor_1 para mejorar la legibilidad e interpretabilidad de nuestro código (recuerda: programa como escribirías en castellano).

# Equivalente a calcular_area(5, 3)
calcular_area(lado_1 = 5, lado_2 = 3)
## $area
## [1] 15
## 
## $lado_1
## [1] 5
## 
## $lado_2
## [1] 3

Parece una tontería lo que hemos hecho pero hemos cruzado una frontera importante: hemos pasado de consumir conocimiento (código de otros paquetes, elaborado por otros/as), a generar conocimiento, creando nuestras propias funciones. En este caso no ganaremos el Nobel por nuestro aporte, pero en un futuro… Si la Unión Europea lo ganó, hay opciones :)

13.2 Variables locales/globales

Un aspecto importante sobre el que reflexionar con las funciones: ¿qué sucede si nombramos a una variable dentro de una función que se nos ha olvidado asignar un valor dentro de la misma? Debemos ser cautos al usar funciones en R, ya que debido a la «regla lexicográfica», si una variable no se define dentro de la función, R buscará dicha variable en el entorno de variables.

Construyamos una función de ejemplo que no toma ningún argumento de entrada: solo imprime el valor de x. Como dentro de la función x no está definida, usará el valor definido fuera de la función.

x <- 1
funcion_ejemplo <- function() {
    
  print(x) # No devuelve nada per se, solo realiza la acción de imprimir en consola
}
funcion_ejemplo()
## [1] 1

Si una variable ya está definida fuera de la función (entorno global), y además es usada dentro de la misma cambiando su valor, el valor de dicha variable solo cambia dentro de la función pero no en el entorno global.

x <- 1
funcion_ejemplo <- function() {
    
  x <- 2
  print(x) # lo que vale dentro
}
funcion_ejemplo() # lo que vale dentro
## [1] 2
print(x) # lo que vale fuera
## [1] 1

Si queremos que además de cambiar localmente lo haga globalmente deberemos usar la doble asignación (<<-).

x <- 1
y <- 2
funcion_ejemplo <- function() {
  
  x <- 3 # no cambia globalmente, solo localmente
  y <<- 0 # cambia globalmente
  print(x)
  print(y)
}

funcion_ejemplo() # lo que vale dentro
## [1] 3
## [1] 0
x # lo que vale fuera
## [1] 1
y # lo que vale fuera
## [1] 0

13.3 📝 Ejercicios

(haz click en las flechas para ver soluciones)

Ejercicio 1: modifica el código inferior para definir una función llamada funcion_suma, de forma que dados dos elementos, devuelve su suma.

  • Solución:
# Definimos función
funcion_suma <- function(x, y) {
  
  # Sumamos
  suma <- x + y
  
  # Devolvemos la salida
  return(suma)
}

# Aplicamos la función
funcion_suma(3, 7)
## [1] 10
# Definimos función
nombre <- function(x, y) {
  
  # Sumamos
  suma <- # código a ejecutar
  
  # ¿Qué devolvemos?
  return()
}

# Aplicamos la función
suma(3, 7)

 

Ejercicio 2: modifica el código inferior para definir una función llamada funcion_producto, de forma que dados dos elementos, devuelve su producto.

  • Solución:
# Definimos función
funcion_producto <- function(x, y) {
  
  # Multiplicamos
  producto <- x * y
  
  # Devolvemos la salida
  return(producto)
}

# Aplicamos la función
funcion_producto(3, -7)
## [1] -21
# Definimos función
nombre <- function(x, y) {
  
  # Multiplicamos
  producto <- # código de la multiplicación
  
  # ¿Qué devolvemos?
  return()
}

# Aplicamos la función
producto(3, -7)

 

Ejercicio 3: modifica el código inferior para definir una función llamada funcion_producto, de forma que dados dos elementos, devuelve su producto, pero que por defecto calcule el cuadrado (es decir, por defecto un solo argumento, y el resultado sea el número por sí mismo)

  • Solución:
# Definimos función
funcion_producto <- function(x, y = x) {
  
  # Multiplicamos
  producto <- x * y
  
  # Devolvemos la salida
  return(producto)
}

# Aplicamos la función
funcion_producto(3) # por defecto x = 3, y = 3
## [1] 9
funcion_producto(3, -7)
## [1] -21
# Definimos función
nombre <- function(x, y) {
  
  # Multiplicamos
  producto <- # código de la multiplicación
  
  # ¿Qué devolvemos?
  return()
}

# Aplicamos la función solo con un argumento
producto(3)

# Aplicamos la función con dos argumentos
producto(3, -7)

 

Ejercicio 4: define una función llamada igualdad_nombres que, dados dos nombres persona_1 e persona_2, nos diga si son iguales o no. Hazlo considerando importantes las mayúsculas, y sin que importen las mayúsculas. Recuerda que con toupper() podemos pasar todo un texto a mayúscula.

  • Solución:
# Distinguiendo mayúsculas
igualdad_nombres <- function(persona_1, persona_2) {
  
  return(persona_1 == persona_2)
}
igualdad_nombres("Javi", "javi")
## [1] FALSE
igualdad_nombres("Javi", "Lucía")
## [1] FALSE
# Sin importar mayúsculas
igualdad_nombres <- function(persona_1, persona_2) {
  
  return(toupper(persona_1) == toupper(persona_2))
}
igualdad_nombres("Javi", "javi")
## [1] TRUE
igualdad_nombres("Javi", "Lucía")
## [1] FALSE

 

Ejercicio 5: define una función llamada pares que, dados dos números x e y, nos diga si la suma de ambos es par o no.

Recuerda que con %% podemos obtener el resto de un número al dividir entre 2.

2 %% 2 # par, resto 0
## [1] 0
3 %% 2 # impar, resto 1
## [1] 1

  • Solución:
# Definimos función
pares <- function(x, y) {
  
  # Sumamos
  suma <- x + y
  
  # Comprobamos si es par
  par <- suma %% 2 == 0
  
  # Devolvemos la salida
  return(par)
}

# Aplicamos la función
pares(1, 3) # suma 4 (par)
## [1] TRUE
pares(2, 7) # suma 9 (impar)
## [1] FALSE

 

Ejercicio 6: define una función llamada pasar_a_celsius que, dada una temperatura \(x\) en Fahrenheit, la convierta a grados Celsius (\(ºC = (ºF - 32) * \frac{5}{9}\)). Aplica la función a la columna Temp del conjunto airquality, e incorpórala al fichero en una nueva columna Temp_Celsius.

  • Solución:
# Definimos función
pasar_a_celsius <- function(x) {
  
  # Temperatura en Celsius
  x_celsius <- (x - 32) * (5 / 9)
  
  # Devolvemos la salida
  return(x_celsius)
}

# Aplicamos la función
pasar_a_celsius(0)
## [1] -17.77778
pasar_a_celsius(80)
## [1] 26.66667
# Aplicamos
data.frame(airquality,
           "Temp_Celsius" = pasar_a_celsius(airquality$Temp))
##     Ozone Solar.R Wind Temp Month Day Temp_Celsius
## 1      41     190  7.4   67     5   1     19.44444
## 2      36     118  8.0   72     5   2     22.22222
## 3      12     149 12.6   74     5   3     23.33333
## 4      18     313 11.5   62     5   4     16.66667
## 5      NA      NA 14.3   56     5   5     13.33333
## 6      28      NA 14.9   66     5   6     18.88889
## 7      23     299  8.6   65     5   7     18.33333
## 8      19      99 13.8   59     5   8     15.00000
## 9       8      19 20.1   61     5   9     16.11111
## 10     NA     194  8.6   69     5  10     20.55556
## 11      7      NA  6.9   74     5  11     23.33333
## 12     16     256  9.7   69     5  12     20.55556
## 13     11     290  9.2   66     5  13     18.88889
## 14     14     274 10.9   68     5  14     20.00000
## 15     18      65 13.2   58     5  15     14.44444
## 16     14     334 11.5   64     5  16     17.77778
## 17     34     307 12.0   66     5  17     18.88889
## 18      6      78 18.4   57     5  18     13.88889
## 19     30     322 11.5   68     5  19     20.00000
## 20     11      44  9.7   62     5  20     16.66667
## 21      1       8  9.7   59     5  21     15.00000
## 22     11     320 16.6   73     5  22     22.77778
## 23      4      25  9.7   61     5  23     16.11111
## 24     32      92 12.0   61     5  24     16.11111
## 25     NA      66 16.6   57     5  25     13.88889
## 26     NA     266 14.9   58     5  26     14.44444
## 27     NA      NA  8.0   57     5  27     13.88889
## 28     23      13 12.0   67     5  28     19.44444
## 29     45     252 14.9   81     5  29     27.22222
## 30    115     223  5.7   79     5  30     26.11111
## 31     37     279  7.4   76     5  31     24.44444
## 32     NA     286  8.6   78     6   1     25.55556
## 33     NA     287  9.7   74     6   2     23.33333
## 34     NA     242 16.1   67     6   3     19.44444
## 35     NA     186  9.2   84     6   4     28.88889
## 36     NA     220  8.6   85     6   5     29.44444
## 37     NA     264 14.3   79     6   6     26.11111
## 38     29     127  9.7   82     6   7     27.77778
## 39     NA     273  6.9   87     6   8     30.55556
## 40     71     291 13.8   90     6   9     32.22222
## 41     39     323 11.5   87     6  10     30.55556
## 42     NA     259 10.9   93     6  11     33.88889
## 43     NA     250  9.2   92     6  12     33.33333
## 44     23     148  8.0   82     6  13     27.77778
## 45     NA     332 13.8   80     6  14     26.66667
## 46     NA     322 11.5   79     6  15     26.11111
## 47     21     191 14.9   77     6  16     25.00000
## 48     37     284 20.7   72     6  17     22.22222
## 49     20      37  9.2   65     6  18     18.33333
## 50     12     120 11.5   73     6  19     22.77778
## 51     13     137 10.3   76     6  20     24.44444
## 52     NA     150  6.3   77     6  21     25.00000
## 53     NA      59  1.7   76     6  22     24.44444
## 54     NA      91  4.6   76     6  23     24.44444
## 55     NA     250  6.3   76     6  24     24.44444
## 56     NA     135  8.0   75     6  25     23.88889
## 57     NA     127  8.0   78     6  26     25.55556
## 58     NA      47 10.3   73     6  27     22.77778
## 59     NA      98 11.5   80     6  28     26.66667
## 60     NA      31 14.9   77     6  29     25.00000
## 61     NA     138  8.0   83     6  30     28.33333
## 62    135     269  4.1   84     7   1     28.88889
## 63     49     248  9.2   85     7   2     29.44444
## 64     32     236  9.2   81     7   3     27.22222
## 65     NA     101 10.9   84     7   4     28.88889
## 66     64     175  4.6   83     7   5     28.33333
## 67     40     314 10.9   83     7   6     28.33333
## 68     77     276  5.1   88     7   7     31.11111
## 69     97     267  6.3   92     7   8     33.33333
## 70     97     272  5.7   92     7   9     33.33333
## 71     85     175  7.4   89     7  10     31.66667
## 72     NA     139  8.6   82     7  11     27.77778
## 73     10     264 14.3   73     7  12     22.77778
## 74     27     175 14.9   81     7  13     27.22222
## 75     NA     291 14.9   91     7  14     32.77778
## 76      7      48 14.3   80     7  15     26.66667
## 77     48     260  6.9   81     7  16     27.22222
## 78     35     274 10.3   82     7  17     27.77778
## 79     61     285  6.3   84     7  18     28.88889
## 80     79     187  5.1   87     7  19     30.55556
## 81     63     220 11.5   85     7  20     29.44444
## 82     16       7  6.9   74     7  21     23.33333
## 83     NA     258  9.7   81     7  22     27.22222
## 84     NA     295 11.5   82     7  23     27.77778
## 85     80     294  8.6   86     7  24     30.00000
## 86    108     223  8.0   85     7  25     29.44444
## 87     20      81  8.6   82     7  26     27.77778
## 88     52      82 12.0   86     7  27     30.00000
## 89     82     213  7.4   88     7  28     31.11111
## 90     50     275  7.4   86     7  29     30.00000
## 91     64     253  7.4   83     7  30     28.33333
## 92     59     254  9.2   81     7  31     27.22222
## 93     39      83  6.9   81     8   1     27.22222
## 94      9      24 13.8   81     8   2     27.22222
## 95     16      77  7.4   82     8   3     27.77778
## 96     78      NA  6.9   86     8   4     30.00000
## 97     35      NA  7.4   85     8   5     29.44444
## 98     66      NA  4.6   87     8   6     30.55556
## 99    122     255  4.0   89     8   7     31.66667
## 100    89     229 10.3   90     8   8     32.22222
## 101   110     207  8.0   90     8   9     32.22222
## 102    NA     222  8.6   92     8  10     33.33333
## 103    NA     137 11.5   86     8  11     30.00000
## 104    44     192 11.5   86     8  12     30.00000
## 105    28     273 11.5   82     8  13     27.77778
## 106    65     157  9.7   80     8  14     26.66667
## 107    NA      64 11.5   79     8  15     26.11111
## 108    22      71 10.3   77     8  16     25.00000
## 109    59      51  6.3   79     8  17     26.11111
## 110    23     115  7.4   76     8  18     24.44444
## 111    31     244 10.9   78     8  19     25.55556
## 112    44     190 10.3   78     8  20     25.55556
## 113    21     259 15.5   77     8  21     25.00000
## 114     9      36 14.3   72     8  22     22.22222
## 115    NA     255 12.6   75     8  23     23.88889
## 116    45     212  9.7   79     8  24     26.11111
## 117   168     238  3.4   81     8  25     27.22222
## 118    73     215  8.0   86     8  26     30.00000
## 119    NA     153  5.7   88     8  27     31.11111
## 120    76     203  9.7   97     8  28     36.11111
## 121   118     225  2.3   94     8  29     34.44444
## 122    84     237  6.3   96     8  30     35.55556
## 123    85     188  6.3   94     8  31     34.44444
## 124    96     167  6.9   91     9   1     32.77778
## 125    78     197  5.1   92     9   2     33.33333
## 126    73     183  2.8   93     9   3     33.88889
## 127    91     189  4.6   93     9   4     33.88889
## 128    47      95  7.4   87     9   5     30.55556
## 129    32      92 15.5   84     9   6     28.88889
## 130    20     252 10.9   80     9   7     26.66667
## 131    23     220 10.3   78     9   8     25.55556
## 132    21     230 10.9   75     9   9     23.88889
## 133    24     259  9.7   73     9  10     22.77778
## 134    44     236 14.9   81     9  11     27.22222
## 135    21     259 15.5   76     9  12     24.44444
## 136    28     238  6.3   77     9  13     25.00000
## 137     9      24 10.9   71     9  14     21.66667
## 138    13     112 11.5   71     9  15     21.66667
## 139    46     237  6.9   78     9  16     25.55556
## 140    18     224 13.8   67     9  17     19.44444
## 141    13      27 10.3   76     9  18     24.44444
## 142    24     238 10.3   68     9  19     20.00000
## 143    16     201  8.0   82     9  20     27.77778
## 144    13     238 12.6   64     9  21     17.77778
## 145    23      14  9.2   71     9  22     21.66667
## 146    36     139 10.3   81     9  23     27.22222
## 147     7      49 10.3   69     9  24     20.55556
## 148    14      20 16.6   63     9  25     17.22222
## 149    30     193  6.9   70     9  26     21.11111
## 150    NA     145 13.2   77     9  27     25.00000
## 151    14     191 14.3   75     9  28     23.88889
## 152    18     131  8.0   76     9  29     24.44444
## 153    20     223 11.5   68     9  30     20.00000