Procesando datos con {tidyverse} - Parte II

Módulo 4 - mutate(), summarise() y group_by()

Pablo Tiscornia

Estación R

2026-03-10

Bienvenidos y bienvenidas

Contacto con Estación R



¿Qué vimos hasta ahora?


✅ La EPH: qué mide, cómo se estructura, cuestionarios


✅ Conceptos básicos de R: valores, vectores, funciones, objetos


Tidyverse: paquetes, importación, la pipa (|>)


select() y filter(): elegir columnas y filtrar filas

Hoja de Ruta - Hoy


🔧 mutate() - crear y editar variables


🔧 case_when() - recodificar categorías

🔧 summarise() - resumir información


🔧 group_by() - operar por grupos

Recordatorio: nuestros datos

library(tidyverse)
eph_ind <- read_csv("datos/eph_individual.csv")


Variable Significado Valores
CH04 Sexo 1=Varón, 2=Mujer
CH06 Edad Años cumplidos
ESTADO Condición de actividad 1=Ocupado, 2=Desocupado, 3=Inactivo
NIVEL_ED Nivel educativo 1 a 7
P21 Ingreso ocupación principal En pesos
REGION Región estadística 1=GBA, 40=NOA, 41=NEA, 42=Cuyo, 43=Pampeana, 44=Patagonia

mutate()

Funciones del paquete {dplyr}


Función Acción
select() selecciona o descarta columnas
filter() selecciona filas
mutate() crea / edita variables
group_by() segmenta en función de una variable
summarise() genera una tabla de resumen

La clase pasada cubrimos select() y filter(). Hoy completamos el kit de herramientas.

mutate() - Crear o editar variables


  • La función tiene la siguiente estructura:
base_de_datos |>
  mutate(variable_nueva = operacion)


mutate() agrega una columna nueva (o modifica una existente) al data frame.

Caso práctico - Variable numérica


  • Queremos calcular la edad al cuadrado (como ejercicio simple):


eph_ind |>
  select(CH04, CH06) |>
  mutate(edad_cuadrado = CH06 * CH06)
# A tibble: 46,050 × 3
    CH04  CH06 edad_cuadrado
   <dbl> <dbl>         <dbl>
 1     2    86          7396
 2     1    68          4624
 3     1    20           400
 4     2    75          5625
 5     2    41          1681
 6     1    42          1764
 7     2    20           400
 8     1    14           196
 9     1    29           841
10     2    27           729
# ℹ 46,040 more rows

Caso práctico - Variable de texto


  • Queremos agregar una columna que indique la fuente de los datos:


eph_ind |>
  select(CH04, CH06, ESTADO) |>
  mutate(fuente = "EPH - T1 2024")
# A tibble: 46,050 × 4
    CH04  CH06 ESTADO fuente       
   <dbl> <dbl>  <dbl> <chr>        
 1     2    86      3 EPH - T1 2024
 2     1    68      1 EPH - T1 2024
 3     1    20      2 EPH - T1 2024
 4     2    75      3 EPH - T1 2024
 5     2    41      1 EPH - T1 2024
 6     1    42      1 EPH - T1 2024
 7     2    20      3 EPH - T1 2024
 8     1    14      3 EPH - T1 2024
 9     1    29      1 EPH - T1 2024
10     2    27      2 EPH - T1 2024
# ℹ 46,040 more rows

mutate() + case_when() = Recodificación


Muchas veces necesitamos transformar códigos numéricos en etiquetas legibles.


La variable ESTADO tiene valores 1, 2, 3 y 4… ¿qué significa cada uno?


Para eso combinamos mutate() con case_when():

mutate(variable_nueva = case_when(
  condicion1 ~ "resultado1",
  condicion2 ~ "resultado2",
  .default = "otro"
))

Caso práctico - Recodificar ESTADO


eph_ind |>
  select(CH04, CH06, ESTADO) |>
  mutate(actividad = case_when(
    ESTADO == 1 ~ "Ocupado",
    ESTADO == 2 ~ "Desocupado",
    ESTADO == 3 ~ "Inactivo",
    ESTADO == 4 ~ "Menor de 10"
  ))
# A tibble: 46,050 × 4
    CH04  CH06 ESTADO actividad 
   <dbl> <dbl>  <dbl> <chr>     
 1     2    86      3 Inactivo  
 2     1    68      1 Ocupado   
 3     1    20      2 Desocupado
 4     2    75      3 Inactivo  
 5     2    41      1 Ocupado   
 6     1    42      1 Ocupado   
 7     2    20      3 Inactivo  
 8     1    14      3 Inactivo  
 9     1    29      1 Ocupado   
10     2    27      2 Desocupado
# ℹ 46,040 more rows

Caso práctico - Crear grupos de edad


  • Para un informe necesitamos agrupar a la población en rangos de edad:


eph_ind |>
  select(CH04, CH06) |>
  mutate(grupo_edad = case_when(
    CH06 < 18              ~ "Menor de 18",
    CH06 >= 18 & CH06 < 65 ~ "18 a 64",
    CH06 >= 65             ~ "65 y más"
  ))
# A tibble: 46,050 × 3
    CH04  CH06 grupo_edad 
   <dbl> <dbl> <chr>      
 1     2    86 65 y más   
 2     1    68 65 y más   
 3     1    20 18 a 64    
 4     2    75 65 y más   
 5     2    41 18 a 64    
 6     1    42 18 a 64    
 7     2    20 18 a 64    
 8     1    14 Menor de 18
 9     1    29 18 a 64    
10     2    27 18 a 64    
# ℹ 46,040 more rows

case_when() con .default


  • .default asigna un valor a todo lo que no matcheó con las condiciones anteriores:


eph_ind |>
  select(CH04, CH06, ESTADO) |>
  mutate(es_ocupado = case_when(
    ESTADO == 1 ~ "Ocupado",
    .default = "No ocupado"
  ))
# A tibble: 46,050 × 4
    CH04  CH06 ESTADO es_ocupado
   <dbl> <dbl>  <dbl> <chr>     
 1     2    86      3 No ocupado
 2     1    68      1 Ocupado   
 3     1    20      2 No ocupado
 4     2    75      3 No ocupado
 5     2    41      1 Ocupado   
 6     1    42      1 Ocupado   
 7     2    20      3 No ocupado
 8     1    14      3 No ocupado
 9     1    29      1 Ocupado   
10     2    27      2 No ocupado
# ℹ 46,040 more rows

Tip: recodificar sexo con case_when()


eph_ind |>
  select(CH04, CH06, ESTADO) |>
  mutate(sexo = case_when(
    CH04 == 1 ~ "Varón",
    CH04 == 2 ~ "Mujer"
  ))
# A tibble: 46,050 × 4
    CH04  CH06 ESTADO sexo 
   <dbl> <dbl>  <dbl> <chr>
 1     2    86      3 Mujer
 2     1    68      1 Varón
 3     1    20      2 Varón
 4     2    75      3 Mujer
 5     2    41      1 Mujer
 6     1    42      1 Varón
 7     2    20      3 Mujer
 8     1    14      3 Varón
 9     1    29      1 Varón
10     2    27      2 Mujer
# ℹ 46,040 more rows

Ejercitación

Ejercitación mutate() + case_when()


  1. Seleccionar las variables CH04, CH06, NIVEL_ED y ESTADO. Crear una variable llamada sexo que recodifique CH04 (1 = “Varón”, 2 = “Mujer”).


  1. Crear una variable grupo_actividad que agrupe ESTADO en dos categorías: “Activo” (1 y 2) y “No activo” (3 y 4). Tip: recordar el operador %in%.


  1. Desafío: Crear una variable mayor_de_edad que valga "Sí" cuando CH06 >= 18 y "No" en caso contrario.

summarise()

summarise() - Resumir información


  • Hasta ahora trabajamos con cada fila del data frame.


  • Pero muchas veces necesitamos resumir: ¿cuál es el promedio? ¿cuántos hay? ¿cuál es el máximo?


  • summarise() colapsa todas las filas en una sola fila con el resumen pedido.

summarise() - Estructura


base_de_datos |>
  summarise(nombre_resumen = funcion(variable))


Funciones comunes para resumir:

Función Acción
mean() Promedio
sum() Suma total
min() / max() Mínimo / Máximo
n() Cantidad de filas

Caso práctico - Promedio de edad


  • ¿Cuál es la edad promedio de los encuestados?
eph_ind |>
  summarise(edad_promedio = mean(CH06))
# A tibble: 1 × 1
  edad_promedio
          <dbl>
1          36.3


Pasamos de 46.050 filas a una sola fila con el resultado.

Caso práctico - Múltiples resúmenes


eph_ind |>
  summarise(edad_promedio = mean(CH06),
            edad_minima   = min(CH06),
            edad_maxima   = max(CH06),
            total_personas = n())
# A tibble: 1 × 4
  edad_promedio edad_minima edad_maxima total_personas
          <dbl>       <dbl>       <dbl>          <int>
1          36.3          -1         101          46050


n() es especial: no recibe argumentos, simplemente cuenta las filas.

Caso práctico - Ingreso de ocupados


  • Para calcular el ingreso promedio, filtramos primero a los ocupados con ingreso positivo:


eph_ind |>
  filter(ESTADO == 1, P21 > 0) |>
  summarise(ingreso_promedio = mean(P21),
            ingreso_mediana  = median(P21))
# A tibble: 1 × 2
  ingreso_promedio ingreso_mediana
             <dbl>           <dbl>
1          305466.          250000


Combinamos filter() + summarise() con la pipa. Cada paso se encadena.

group_by()

group_by() - Operar por grupos


  • summarise() nos da un resumen general. Pero muchas veces queremos comparar entre grupos.


  • ¿Cuál es el ingreso promedio por sexo?
  • ¿Cuántas personas hay por región?


  • group_by() divide el data frame en grupos antes de resumir.

Sin agrupar vs. agrupado


Sin agrupar:

eph_ind |>
  summarise(
    edad_prom = mean(CH06)
  )
# A tibble: 1 × 1
  edad_prom
      <dbl>
1      36.3

Agrupado por sexo:

eph_ind |>
  group_by(CH04) |>
  summarise(
    edad_prom = mean(CH06)
  )
# A tibble: 2 × 2
   CH04 edad_prom
  <dbl>     <dbl>
1     1      34.9
2     2      37.6

Caso práctico - Ingreso por sexo


eph_ind |>
  filter(ESTADO == 1, P21 > 0) |>
  group_by(CH04) |>
  summarise(ingreso_promedio = mean(P21),
            cantidad = n())
# A tibble: 2 × 3
   CH04 ingreso_promedio cantidad
  <dbl>            <dbl>    <int>
1     1          344550.     8976
2     2          258920.     7537


Recordar: CH04 = 1 (Varón), 2 (Mujer). Podemos mejorar esto con mutate() + case_when().

Combinando todo: un análisis más completo


eph_ind |>
  filter(ESTADO == 1, P21 > 0) |>
  mutate(sexo = case_when(CH04 == 1 ~ "Varón",
                          CH04 == 2 ~ "Mujer")) |>
  group_by(sexo) |>
  summarise(ingreso_promedio = mean(P21),
            cantidad = n())
# A tibble: 2 × 3
  sexo  ingreso_promedio cantidad
  <chr>            <dbl>    <int>
1 Mujer          258920.     7537
2 Varón          344550.     8976

Agrupar por más de una variable


  • Podemos agrupar por dos o más variables a la vez:
eph_ind |>
  filter(ESTADO == 1, P21 > 0) |>
  mutate(sexo = case_when(CH04 == 1 ~ "Varón",
                          CH04 == 2 ~ "Mujer")) |>
  group_by(sexo, REGION) |>
  summarise(ingreso_promedio = mean(P21),
            cantidad = n())
# A tibble: 12 × 4
# Groups:   sexo [2]
   sexo  REGION ingreso_promedio cantidad
   <chr>  <dbl>            <dbl>    <int>
 1 Mujer      1          321779.     1043
 2 Mujer     40          202567.     1809
 3 Mujer     41          188494.      793
 4 Mujer     42          242039.      775
 5 Mujer     43          268307.     2179
 6 Mujer     44          349388.      938
 7 Varón      1          446867.     1149
 8 Varón     40          253146.     2141
 9 Varón     41          240207.      984
10 Varón     42          323336.      981
11 Varón     43          358655.     2598
12 Varón     44          491457.     1123

Alternativa moderna: .by


Desde dplyr 1.1.0, existe una forma más directa: el argumento .by dentro de summarise().


Forma clásica:

eph_ind |>
  group_by(CH04) |>
  summarise(
    edad_prom = mean(CH06)
  )

Con .by:

eph_ind |>
  summarise(
    edad_prom = mean(CH06),
    .by = CH04
  )


Ambas hacen lo mismo. .by es más conciso y no requiere un paso extra. Van a encontrar ambas formas en la práctica.

.by con múltiples variables


eph_ind |>
  filter(ESTADO == 1, P21 > 0) |>
  mutate(sexo = case_when(CH04 == 1 ~ "Varón",
                          CH04 == 2 ~ "Mujer")) |>
  summarise(ingreso_promedio = mean(P21),
            cantidad = n(),
            .by = c(sexo, REGION))
# A tibble: 12 × 4
   sexo  REGION ingreso_promedio cantidad
   <chr>  <dbl>            <dbl>    <int>
 1 Varón     43          358655.     2598
 2 Mujer     40          202567.     1809
 3 Varón     40          253146.     2141
 4 Mujer     44          349388.      938
 5 Mujer      1          321779.     1043
 6 Mujer     42          242039.      775
 7 Varón     42          323336.      981
 8 Varón     41          240207.      984
 9 Mujer     43          268307.     2179
10 Varón      1          446867.     1149
11 Mujer     41          188494.      793
12 Varón     44          491457.     1123

Ejercitación

Ejercitación summarise() + group_by()


  1. Calcular la edad promedio y la cantidad de personas para toda la base.


  1. Calcular la cantidad de personas por condición de actividad (ESTADO). Tip: summarise(n = n(), .by = ESTADO).


  1. Filtrar la población ocupada (ESTADO == 1) con ingreso positivo (P21 > 0). Calcular el ingreso promedio por región (REGION).


  1. Desafío: Al ejercicio anterior, agregarle una recodificación de CH04 a sexo (“Varón”/“Mujer”) y calcular el ingreso promedio por sexo y región.

tidyverse en acción

Un análisis completo con la EPH


Pregunta: ¿Cuál es el ingreso promedio de la población ocupada por sexo y grupo de edad?


Combinamos todo lo aprendido en un solo pipeline:

Paso a paso


eph_ind |>
  filter(ESTADO == 1, P21 > 0) |>
  select(CH04, CH06, P21) |>
  mutate(
    sexo = case_when(
      CH04 == 1 ~ "Varón",
      CH04 == 2 ~ "Mujer"),
    grupo_edad = case_when(
      CH06 < 30             ~ "Joven",
      CH06 >= 30 & CH06 < 50 ~ "Adulto",
      CH06 >= 50             ~ "Mayor")
  ) |>
  summarise(
    ingreso_promedio = mean(P21),
    personas = n(),
    .by = c(sexo, grupo_edad)
  )
# A tibble: 6 × 4
  sexo  grupo_edad ingreso_promedio personas
  <chr> <chr>                 <dbl>    <int>
1 Varón Mayor               381930.     2363
2 Mujer Adulto              272637.     4028
3 Varón Adulto              366886.     4532
4 Varón Joven               253464.     2081
5 Mujer Mayor               275972.     1956
6 Mujer Joven               201865.     1553

Lo que logramos hoy


mutate() + case_when() — crear variables y recodificar


summarise() — resumir datos (promedios, conteos, etc.)


group_by() / .by — operar por grupos


✅ Combinar todo en un pipeline completo con la EPH

Para la semana que viene…

Próximo encuentro: Proyectos, ggplot2 y TP integrador


📁 Cómo organizar un proyecto de R profesionalmente


📊 ggplot2: visualización de datos


🎯 TP integrador: aplicando todo lo aprendido


🏁 Último encuentro del curso

¡Gracias!



Nos vemos el martes 10 de marzo


📧 pablotiscornia@estacion-r.com

💬 Slack de Estación R