Capítulo 13 Funciones
Scripts usados:
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 reservadafunction()
. - 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 comandoreturn()
se introducirán los argumentos de salida, que puede ser un número, undata.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
.
- Nombre –>
calcular_area
- Argumentos –>
lado_1, lado_2
- Código –>
area <- lado_1 * lado_2
- 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