Capítulo 13 Funciones
Scripts usados:
En R
no solo podemos usar las funciones predeterminadas que vienen ya cargadas, como o las de los paquetes que instalamos, como sum()
o mean()
, sino que 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 lo que queremos que devuelva la función.
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á la salida de la función, que puede ser un número, undata.frame
, 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: los argumentos de entrada serán los lados (lado_1
y lado_2
), y el valor a devolver será el área lado_1 * lado_2
(el producto de los lados).
# 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 la 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? Con el 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
Imagina ahora que nos damos cuenta que el 90% de las veces el área que nos toca calcular fuese la de un cuadrado (es decir, solo necesitamos un argumento, un lado): R
nos permite definir argumentos por defecto en la función (tomarán dicho valor salvo que le asignemos otro). ¿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
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).
calcular_area(lado_1 = 5) # si no indicamos nada, lado_2 = lado_1
## [1] 25
Compliquemos un poco la función y añadamos en la salida los valores de cada lado, etiquetados como lado_1
y lado_2
.
# 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(c("area" = area, "lado_1" = lado_1, "lado_2" = lado_2))
}
Veamos que nos devuelve ahora
salida <- calcular_area(5, 3)
salida
## area lado_1 lado_2
## 15 5 3
salida["area"]
## area
## 15
salida["lado_1"]
## lado_1
## 5
salida["lado_2"]
## lado_2
## 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).
calcular_area(lado_1 = 5, lado_2 = 3)
## area lado_1 lado_2
## 15 5 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
Ejercicio 1: modifica el código inferior para definir una función llamada
funcion_suma
, de forma que dados dos elementos, devuelve su suma.
# Definimos función
nombre <- function(x, y) {
# Sumamos
suma <- # código a ejecutar
# ¿Qué devolvemos?
return()
}
# Aplicamos la función
suma(3, 7)
- 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
&nsbp;
Ejercicio 2: modifica el código inferior para definir una función llamada
funcion_producto
, de forma que dados dos elementos, devuelve su producto.
# 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)
- 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
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)
# 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)
- 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
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