Apunte 5 — Funciones de dplyr para manipular datos

Analítica de Personas · Semestre otoño 2026 · Semana 2 · Prof. René Gempp

En el Apunte 1 cubrimos las funciones básicas de dplyr: count(), filter(), group_by(), summarise(), select(), mutate() y arrange(). Este apunte amplía el repertorio con funciones que usarás constantemente a partir de la Clase 2.

1. mutate() en profundidad

Ya sabes que mutate() crea o modifica columnas. Aquí cubrimos sus variantes más útiles.

if_else() — Condición binaria

Crea una nueva variable con dos posibles valores según una condición. Es como un SI() de Excel:

# Crear flag de alto desempeño
datos |>
  mutate(
    alto_desempeno = if_else(evaluacion_desempeno >= 4, "Alto", "No alto")
  )
ArgumentoQué esEjemplo
1° — condiciónUna expresión lógica (TRUE/FALSE)evaluacion_desempeno >= 4
2° — valor si TRUEQué asignar cuando la condición se cumple"Alto"
3° — valor si FALSEQué asignar cuando no se cumple"No alto"
¿if_else() o ifelse()? R tiene dos funciones: ifelse() (base R) e if_else() (dplyr). La de dplyr es más estricta: exige que ambos valores sean del mismo tipo (ambos texto, ambos número, etc.), lo que ayuda a prevenir errores. Usaremos siempre if_else() del tidyverse.

case_when() — Múltiples condiciones

Cuando necesitas más de dos opciones, case_when() es tu herramienta. Es como un SI anidado de Excel, pero legible:

# Crear tramos de antigüedad
datos |>
  mutate(
    tramo_antiguedad = case_when(
      antiguedad_anios < 1   ~ "Menos de 1 año",
      antiguedad_anios < 3   ~ "1 a 3 años",
      antiguedad_anios < 5   ~ "3 a 5 años",
      antiguedad_anios < 10  ~ "5 a 10 años",
      TRUE                   ~ "10 o más años"   # ← caso por defecto
    )
  )

La sintaxis es condición ~ valor_a_asignar. R evalúa las condiciones de arriba hacia abajo y asigna la primera que sea verdadera. TRUE ~ al final atrapa todo lo que no matcheó antes (como un "else").

Atención al orden de las condiciones Las condiciones se evalúan en orden. Si alguien tiene 0.5 años de antigüedad, la primera condición (< 1) ya es TRUE, así que obtiene "Menos de 1 año" y las siguientes no se evalúan. Si pusieras < 10 primero, todos los de menos de 10 caerían ahí.
# Ejemplo más complejo: clasificar tipo de rotación
datos |>
  mutate(
    tipo_rotacion = case_when(
      rotacion == "No"                                       ~ "Activo",
      tipo_salida == "Involuntaria"                          ~ "Involuntaria",
      tipo_salida == "Voluntaria" & alto_desempeno == "Alto" ~ "Vol. disfuncional",
      tipo_salida == "Voluntaria" & alto_desempeno != "Alto" ~ "Vol. funcional"
    )
  )

case_when() con =

case_when(
  edad < 30 = "Joven"  # ERROR
)

Usa = en vez de ~

case_when() con ~

case_when(
  edad < 30 ~ "Joven"  # CORRECTO
)

La tilde ~ es el asignador de case_when()

2. arrange() y slice_*() — Ordenar y extraer

arrange() — Ordenar filas

# Ordenar por edad (ascendente, por defecto)
datos |> arrange(edad)

# Ordenar por ingreso (descendente)
datos |> arrange(desc(ingreso_mensual))

# Ordenar por dos variables: primero departamento, luego ingreso descendente
datos |> arrange(departamento, desc(ingreso_mensual))

slice_max() y slice_min() — Los N más altos/bajos

# Los 5 empleados con mayor ingreso
datos |>
  slice_max(ingreso_mensual, n = 5)

# Los 3 con menor satisfacción
datos |>
  slice_min(satisfaccion_laboral, n = 3)

# Top 3 por departamento (combinado con group_by)
datos |>
  group_by(departamento) |>
  slice_max(ingreso_mensual, n = 3)
¿arrange() + head() o slice_max()? Ambos pueden dar el mismo resultado, pero slice_max() es más directo y funciona con group_by() (te da el top N dentro de cada grupo). Prefiere slice_max() cuando quieres un ranking.

Otras funciones slice_*()

FunciónQué haceEjemplo
slice_head(n = 5)Las primeras N filasEquivale a head(5)
slice_tail(n = 5)Las últimas N filasEquivale a tail(5)
slice_sample(n = 10)N filas al azarMuestra aleatoria rápida
slice_max(x, n = 5)Las N filas con mayor valor de xTop 5 ingresos
slice_min(x, n = 5)Las N filas con menor valor de xBottom 5 satisfacción

3. rename() y relocate() — Renombrar y reordenar columnas

# Renombrar columnas (nuevo_nombre = nombre_actual)
datos |>
  rename(
    sueldo = ingreso_mensual,
    depto  = departamento
  )

# Mover columnas al principio
datos |>
  relocate(rotacion, tipo_salida, .before = edad)

# Mover columnas al final
datos |>
  relocate(id_empleado, nombre, .after = last_col())

4. distinct() — Valores únicos

# ¿Cuántos departamentos distintos hay?
datos |>
  distinct(departamento)

# Combinaciones únicas de departamento y nivel jerárquico
datos |>
  distinct(departamento, nivel_jerarquico)

# Obtener una fila por empleado (eliminar duplicados si los hay)
datos |>
  distinct(id_empleado, .keep_all = TRUE)
# .keep_all = TRUE conserva todas las columnas, no solo la clave

5. pull() — Extraer una columna como vector

select() devuelve un tibble (tabla). A veces necesitas un vector (un solo valor o lista de valores). Para eso existe pull():

# Esto devuelve un tibble de 1 columna:
datos |> select(edad)

# Esto devuelve un vector numérico:
datos |> pull(edad)

# Útil para extraer un valor calculado
tasa <- datos |>
  summarise(tasa_rot = mean(rotacion == "Sí")) |>
  pull(tasa_rot)

# Ahora 'tasa' es un número (0.272), no una tabla
paste0("La tasa de rotación es ", scales::percent(tasa))

6. across() — Aplicar una función a múltiples columnas

Cuando necesitas calcular lo mismo para varias columnas a la vez, across() evita repetir código:

# Promedio de edad, antigüedad e ingreso por departamento
datos |>
  group_by(departamento) |>
  summarise(
    across(
      c(edad, antiguedad_anios, ingreso_mensual),  # columnas
      mean                                          # función
    )
  )

# También puedes usar selectores:
datos |>
  group_by(departamento) |>
  summarise(
    across(where(is.numeric), mean)
    # Aplica mean() a TODAS las columnas numéricas
  )

# Con función personalizada (redondear a 1 decimal)
datos |>
  group_by(departamento) |>
  summarise(
    across(where(is.numeric), \(x) round(mean(x), 1))
  )

7. n_distinct() — Contar valores únicos

# ¿Cuántos cargos distintos hay por departamento?
datos |>
  group_by(departamento) |>
  summarise(
    n_empleados   = n(),
    n_cargos      = n_distinct(cargo),
    n_oficinas    = n_distinct(oficina)
  )

8. Resumen: mapa de funciones de dplyr

Quiero...FunciónApunte
Contar filas por grupocount()Apunte 1
Filtrar filas por condiciónfilter()Apunte 1
Agrupar y calcular resúmenesgroup_by() + summarise()Apunte 1
Elegir columnasselect()Apunte 1
Crear/modificar columnasmutate()Apuntes 1 y 5
Condición binaria → nueva variableif_else()Apunte 5
Múltiples condiciones → nueva variablecase_when()Apunte 5
Ordenar filasarrange()Apuntes 1 y 5
Top N por valorslice_max() / slice_min()Apunte 5
Renombrar columnasrename()Apunte 5
Reordenar columnasrelocate()Apunte 5
Valores únicosdistinct()Apunte 5
Extraer vector de un tibblepull()Apunte 5
Aplicar función a muchas columnasacross()Apunte 5
Contar valores únicosn_distinct()Apunte 5
Unir tablas por claveleft_join() y familiaApunte 4