Capítulo25 Funciones

El tema proviene de los siguientes sitios.

English: https://r4ds.had.co.nz/functions.html

Español: https://es.r4ds.hadley.nz/funciones.html


Fecha de la última revisión

## [1] "2026-07-29"

25.1 Temas:

  • ¿Cuándo escribir una función?
  • La anatomía de una función: nombre, argumentos y cuerpo
  • Ejecución condicional: if y else
  • Argumentos y valores por defecto
  • Valores de retorno
  • Un vistazo a los vectores

En el capítulo de tidyverse avanzado verás funciones más sofisticadas que usan tidy evaluation (el operador {{ }}). Aquí construimos la base.


25.2 ¿Cuándo escribir una función?

Una función te permite darle un nombre a un bloque de código para poder reutilizarlo. La regla práctica es: si copiaste y pegaste el mismo código más de dos veces, escribe una función. Copiar y pegar es una de las fuentes de errores más comunes, porque es fácil olvidar cambiar el nombre de una variable en una de las copias.

Observa este código que reescala tres columnas para que queden entre 0 y 1:

df <- data.frame(
  a = c(2, 5, 8, 1),
  b = c(10, 20, 30, 40),
  c = c(-5, 0, 5, 10)
)

df$a <- (df$a - min(df$a)) / (max(df$a) - min(df$a))
df$b <- (df$b - min(df$b)) / (max(df$b) - min(df$b))
df$c <- (df$c - min(df$c)) / (max(df$c) - min(df$c))
df
##           a         b         c
## 1 0.1428571 0.0000000 0.0000000
## 2 0.5714286 0.3333333 0.3333333
## 3 1.0000000 0.6666667 0.6666667
## 4 0.0000000 1.0000000 1.0000000

¿Notaste el patrón repetido? Eso es una señal clara de que conviene una función.


25.3 La anatomía de una función

Toda función tiene tres partes:

  1. Un nombre (aquí, reescalar01).
  2. Los argumentos que van dentro de function( ) (aquí, x).
  3. El cuerpo, el código dentro de las llaves { }.
reescalar01 <- function(x) {
  rango <- range(x, na.rm = TRUE)
  (x - rango[1]) / (rango[2] - rango[1])
}

# Probar la función con un ejemplo cuya respuesta ya conocemos
reescalar01(c(0, 5, 10))
## [1] 0.0 0.5 1.0

Ahora el código repetido se reduce a esto, mucho más fácil de leer y de corregir:

df <- data.frame(
  a = c(2, 5, 8, 1),
  b = c(10, 20, 30, 40),
  c = c(-5, 0, 5, 10)
)

df$a <- reescalar01(df$a)
df$b <- reescalar01(df$b)
df$c <- reescalar01(df$c)
df
##           a         b         c
## 1 0.1428571 0.0000000 0.0000000
## 2 0.5714286 0.3333333 0.3333333
## 3 1.0000000 0.6666667 0.6666667
## 4 0.0000000 1.0000000 1.0000000

Una función siempre se debe probar con valores cuya respuesta ya conoces antes de confiar en ella.


25.4 Ejecución condicional: if y else

Dentro de una función puedes tomar decisiones con if y else.

signo <- function(x) {
  if (x > 0) {
    "positivo"
  } else if (x < 0) {
    "negativo"
  } else {
    "cero"
  }
}

signo(7)
## [1] "positivo"
signo(-3)
## [1] "negativo"
signo(0)
## [1] "cero"

25.5 Argumentos y valores por defecto

Los argumentos pueden tener un valor por defecto, que se usa cuando quien llama la función no especifica ese argumento.

# Calcular la media recortada; por defecto recorta un 10%
media_recortada <- function(x, recorte = 0.1) {
  mean(x, trim = recorte, na.rm = TRUE)
}

valores <- c(1, 2, 3, 4, 5, 100)  # el 100 es un valor atípico
media_recortada(valores)              # usa recorte = 0.1
## [1] 19.16667
media_recortada(valores, recorte = 0.2)
## [1] 3.5
mean(valores)                          # comparación: la media normal
## [1] 19.16667

25.6 Valores de retorno

Una función en R devuelve el valor de la última línea de su cuerpo. También puedes usar return() para devolver un valor antes del final, por ejemplo para salir temprano en un caso especial.

coef_variacion <- function(x) {
  if (mean(x, na.rm = TRUE) == 0) {
    return(NA)   # evitar división por cero
  }
  sd(x, na.rm = TRUE) / mean(x, na.rm = TRUE)
}

coef_variacion(c(2, 4, 4, 4, 5, 5, 7, 9))
## [1] 0.427618
coef_variacion(c(-5, 0, 5))   # la media es 0 -> NA
## [1] NA

25.7 Un vistazo a los vectores

Las funciones trabajan sobre vectores. Conocer los tipos básicos de vectores atómicos explica muchos “comportamientos raros” de R.

lgl <- c(TRUE, FALSE, NA)       # lógico
int <- c(1L, 5L, 10L)           # entero
dbl <- c(1.5, 2.7, 3.14)        # doble (números reales)
chr <- c("a", "b", "c")         # cadena de caracteres

typeof(lgl)
## [1] "logical"
typeof(int)
## [1] "integer"
typeof(dbl)
## [1] "double"
typeof(chr)
## [1] "character"

Coerción: cuando mezclas tipos, R convierte todo al tipo “más flexible”.

c(1, 2, "tres")     # todo se convierte en texto
## [1] "1"    "2"    "tres"
c(TRUE, 1L, 2.5)    # lógico -> entero -> doble
## [1] 1.0 1.0 2.5

Valores faltantes (NA): casi cualquier operación con NA da NA. Por eso muchas funciones tienen el argumento na.rm = TRUE.

x <- c(1, 2, NA, 4)
mean(x)                # NA
## [1] NA
mean(x, na.rm = TRUE)  # 2.333...
## [1] 2.333333
is.na(x)               # ¿cuáles son NA?
## [1] FALSE FALSE  TRUE FALSE

  1. Ejercicios:

Hacer los ejercicios en la sección 19.2 del libro en español.


  1. Ejercicios:

Escribe una función fahrenheit_a_celsius() que reciba una temperatura en grados Fahrenheit y devuelva grados Celsius. La fórmula es \(C = (F - 32) \times 5/9\). Pruébala con 32 (debe dar 0) y con 212 (debe dar 100).


  1. Ejercicios:

Hacer los ejercicios en la sección 19.4 del libro en español.