Manipulación de Datos con dplyr

Capacitación en R

Introducción

¡Bienvenidos!

En este módulo, aprenderemos cómo manipular (limpiar, transformar y preparar) datos tributarios usando dplyr.

¿Qué significa “manipulación de datos”?

La manipulación de datos es el proceso de transformar datos brutos en un formato que esté listo para análisis.

Piénsalo como preparar ingredientes antes de cocinar:

  • Lavar verduras 🥕 → Eliminar datos malos
  • Cortar ingredientes 🔪 → Seleccionar lo que necesitas
  • Mezclar ingredientes 🍜 → Combinar conjuntos de datos

Al final de este módulo, podrás:

  • Filtrar, seleccionar y transformar datos tributarios
  • Crear nuevas variables y transformar las existentes
  • Trabajar con fechas para análisis de presentación de impuestos
  • Construir flujos de trabajo completos de procesamiento de datos

¿Por qué dplyr?

dplyr es parte del tidyverse - una colección de paquetes de R diseñados para trabajar juntos sin problemas.

Ventajas:

Legible - los verbos coinciden con lo que quieres hacer

Consistente - sintaxis similar en todas las operaciones

Amigable para principiantes - claro y lógico

Bien documentado - toneladas de recursos

# ¡Código similar al inglés!
tax_data %>%
  filter(filing_year == 2023) %>%
  select(firm_id, vat_outputs) %>%
  arrange(desc(vat_outputs))

# "Toma tax_data, LUEGO
#  filtra a 2023, LUEGO
#  selecciona estas columnas, LUEGO
#  ordena por monto"

Note

¡Explicaremos qué significa %>% en un momento!

Almacenando Tu Trabajo: Asignación en R

Antes de sumergirnos en la manipulación de datos, necesitamos entender un concepto crucial:

¡Los Cambios No se Guardan a Menos que los Guardes!

Cuando transformas datos en R, los cambios NO se guardan automáticamente. Debes usar el operador de asignación <- para almacenar resultados.

# Esto muestra el resultado pero NO lo guarda
panel_vat %>%
  filter(vat_outputs > 40000)

# ¡La próxima vez que uses panel_vat, esos cambios DESAPARECIERON!

Cómo Funciona la Asignación

El operador de asignación <- almacena resultados en un objeto:

# Crear un nuevo objeto con datos filtrados
high_vat <- panel_vat %>%
  filter(vat_outputs > 40000)

# Ahora podemos usar high_vat más tarde
nrow(high_vat)  # Verificar cuántas filas
[1] 211

También puedes sobrescribir el original:

# Esto REEMPLAZA panel_vat con la versión filtrada
panel_vat <- panel_vat %>%
  filter(vat_outputs > 40000)

# ¡Ten cuidado! Los datos originales ahora se perdieron.

Warning

¡Sobrescribir es permanente! Si no estás seguro, crea un nuevo objeto en su lugar.

Cuándo Crear Nuevo vs. Sobrescribir

Crea un NUEVO objeto cuando:

  • Quieras mantener los datos originales
  • Estés probando diferentes enfoques
  • Estés explorando o probando
vat_2023 <- panel_vat %>%
  filter(filing_year == 2023)

# ¡El panel_vat original todavía está ahí!

Sobrescribe el MISMO objeto cuando:

  • Estés limpiando datos paso a paso
  • Estés agregando columnas calculadas permanentes
  • Estés seguro de que no necesitas el original
# Agregar columna de año permanentemente
panel_vat <- panel_vat %>%
  mutate(filing_year = year(declaration_date))

# ¡Ahora panel_vat tiene la columna filing_year!

Práctica: Atajo de Teclado

El operador de asignación <- tiene un atajo de teclado:

Tip

Alt + - (menos) (Windows/Linux)

Option + - (menos) (Mac)

¡Esto escribe <- automáticamente!

Practiquemos el concepto:

# Crear una variable con el año extraído
panel_vat <- panel_vat %>%
  mutate(filing_year = year(declaration_date))

# Verificar que está ahí
"filing_year" %in% names(panel_vat)
[1] TRUE

El Operador Pipe: %>%

El operador pipe (%>%) es la clave para escribir código claro y legible.

Piénsalo como “y luego”:

# Sin pipes - ¡difícil de leer!
arrange(select(filter(tax_data, filing_year == 2023), firm_id, vat_outputs), desc(vat_outputs))

# Con pipes - ¡mucho más claro!
tax_data %>%
  filter(filing_year == 2023) %>%
  select(firm_id, vat_outputs) %>%
  arrange(desc(vat_outputs))

Cómo leerlo:

  1. Comienza con tus datos: tax_data
  2. LUEGO (%>%) filtra a 2023
  3. LUEGO (%>%) selecciona columnas específicas
  4. LUEGO (%>%) ordena los resultados

Tip

Atajo de teclado: Ctrl + Shift + M (Windows) o Cmd + Shift + M (Mac)

Ejemplo de Pipe: Café Matutino ☕

Entendamos los pipes con un ejemplo cotidiano:

Haciendo café (sin pipes):

drink(pour(brew(grind(beans))))
# ¡Tienes que leer de adentro hacia afuera! ¡Confuso!

Haciendo café (con pipes):

beans %>%
  grind() %>%
  brew() %>%
  pour() %>%
  drink()

# ¡Lee de arriba a abajo - como seguir una receta!

La misma lógica para datos tributarios:

panel_vat %>%
  mutate(filing_year = year(declaration_date)) %>%  # Extraer año primero
  filter(filing_year == 2023) %>%                   # Luego filtrar
  arrange(desc(vat_outputs))                        # Luego ordenar

Filtrando Filas: filter()

Filtrado Básico

filter() selecciona filas basándose en condiciones:

# Obtener solo declaraciones de 2023
vat_2023 <- panel_vat %>%
  filter(filing_year == 2023)

nrow(vat_2023)  # ¿Cuántas filas quedaron?
[1] 339

Operadores de comparación comunes:

  • == igual a
  • != no igual a
  • > mayor que
  • < menor que
  • >= mayor o igual que
  • <= menor o igual que

Múltiples Condiciones

Usar comas o & para AND (ambas condiciones deben ser verdaderas):

# Grandes contribuyentes en 2023
large_vat_2023 <- panel_vat %>%
  filter(filing_year == 2023, vat_outputs > 40000)

nrow(large_vat_2023)
[1] 71

Usar | para OR (cualquier condición puede ser verdadera):

# Muy bajos o muy altos
extreme_vat <- panel_vat %>%
  filter(vat_outputs < 5000 | vat_outputs > 50000)

nrow(extreme_vat)
[1] 84

Filtrando con %in%

Verificar si los valores coinciden con una lista:

# Empresas específicas
selected_firms <- c("FIRM_001", "FIRM_003", "FIRM_005")

firms_subset <- panel_vat %>%
  filter(firm_id %in% selected_firms)

unique(firms_subset$firm_id)
character(0)

Negar con ! (no en la lista):

# Todos excepto estas empresas
other_firms <- panel_vat %>%
  filter(!firm_id %in% selected_firms)

nrow(other_firms)
[1] 1000

Ejercicio 1: Práctica de Filtrado

Puedes encontrar el ejercicio en la carpeta “Exercises/exercise_01_template.R”

10:00

Tus tareas:

Usando panel_vat:

  1. Filtrar declaraciones donde vat_outputs > 30000
  2. Filtrar empresas que declararon en Q1 de 2023 (filing_quarter == 1 Y filing_year == 2023)
  3. Encontrar declaraciones con IVA neto negativo (vat_outputs - vat_inputs < 0)
  4. Bonus: Encontrar declaraciones de las 5 empresas principales por total de vat_outputs

Sugerencia: Para el bonus, usa group_by(), summarize(), arrange(), y head()

Ejercicio 1: Soluciones

# 1. Filtrar outputs grandes
grandes_outputs <- panel_vat %>%
  filter(vat_outputs > 30000)
nrow(grandes_outputs)

# 2. Filtrar Q1 de 2023
q1_2023 <- panel_vat %>%
  filter(filing_year == 2023, filing_quarter == 1)
nrow(q1_2023)

# 3. IVA neto negativo
iva_negativo <- panel_vat %>%
  filter(vat_outputs - vat_inputs < 0)
nrow(iva_negativo)

# 4. Bonus: Top 5 empresas
top_firms <- panel_vat %>%
  group_by(firm_id) %>%
  summarize(total_vat = sum(vat_outputs, na.rm = TRUE), .groups = "drop") %>%
  arrange(desc(total_vat)) %>%
  head(5)

# Declaraciones de estas empresas
declaraciones_top <- panel_vat %>%
  filter(firm_id %in% top_firms$firm_id)

Seleccionando Columnas: select()

Selección Básica

select() elige qué columnas mantener:

# Mantener solo columnas específicas
vat_simple <- panel_vat %>%
  select(firm_id, declaration_date, vat_outputs, vat_inputs)

names(vat_simple)
[1] "firm_id"          "declaration_date" "vat_outputs"      "vat_inputs"      

Excluir columnas con -:

# Mantener todo excepto filing_month
vat_no_month <- panel_vat %>%
  select(-filing_month)

names(vat_no_month)
[1] "firm_id"            "declaration_date"   "vat_inputs"        
[4] "vat_outputs"        "reimbursement_date" "filing_year"       
[7] "filing_quarter"    

Funciones Auxiliares de Select

Seleccionar columnas por patrón:

# Todas las columnas que empiezan con "vat"
vat_cols <- panel_vat %>%
  select(starts_with("vat"))

names(vat_cols)
[1] "vat_inputs"  "vat_outputs"

Otras funciones auxiliares útiles:

# Columnas que terminan con "_date"
select(ends_with("_date"))

# Columnas que contienen "filing"
select(contains("filing"))

# Reordenar - poner firm_id primero, luego todo lo demás
select(firm_id, everything())

Renombrar Mientras se Selecciona

Puedes renombrar columnas dentro de select():

# Seleccionar y renombrar
vat_renamed <- panel_vat %>%
  select(
    empresa = firm_id,
    fecha = declaration_date,
    iva_cobrado = vat_outputs,
    iva_pagado = vat_inputs
  )

names(vat_renamed)
[1] "empresa"     "fecha"       "iva_cobrado" "iva_pagado" 

O usar rename() para mantener todas las columnas:

# Renombrar sin eliminar otras columnas
panel_vat %>%
  rename(iva_cobrado = vat_outputs, iva_pagado = vat_inputs)

Creando/Modificando Columnas: mutate()

Creando Nuevas Columnas

mutate() es tu herramienta más importante - crea o modifica columnas:

# Calcular IVA neto
vat_with_net <- panel_vat %>%
  mutate(net_vat = vat_outputs - vat_inputs)

# Verificar las nuevas columnas
vat_with_net %>%
  select(firm_id, vat_outputs, vat_inputs, net_vat) %>%
  head(3)
     firm_id vat_outputs vat_inputs net_vat
      <char>       <int>      <int>   <int>
1: FIRM_0096       45914      45262     652
2: FIRM_0081       29661       9225   20436
3: FIRM_0024       10005      15289   -5284

Múltiples Mutaciones

Crear varias columnas a la vez:

# Agregar múltiples cálculos
vat_enhanced <- panel_vat %>%
  mutate(
    net_vat = vat_outputs - vat_inputs,
    vat_ratio = vat_inputs / vat_outputs,
    is_large = vat_outputs > 40000
  )

vat_enhanced %>%
  select(firm_id, net_vat, vat_ratio, is_large) %>%
  head(3)
     firm_id net_vat vat_ratio is_large
      <char>   <int>     <num>   <lgcl>
1: FIRM_0096     652 0.9857995     TRUE
2: FIRM_0081   20436 0.3110145    FALSE
3: FIRM_0024   -5284 1.5281359    FALSE

Tip

Puedes referirte a columnas recién creadas en la misma declaración mutate!

Lógica Condicional: if_else()

Crear columnas basadas en condiciones:

# Categorizar contribuyentes
vat_categorized <- panel_vat %>%
  mutate(
    taxpayer_size = if_else(
      vat_outputs > 40000,
      "Grande",
      "Pequeño"
    )
  )

vat_categorized %>%
  select(firm_id, vat_outputs, taxpayer_size) %>%
  head(3)
     firm_id vat_outputs taxpayer_size
      <char>       <int>        <char>
1: FIRM_0096       45914        Grande
2: FIRM_0081       29661       Pequeño
3: FIRM_0024       10005       Pequeño

Sintaxis:

if_else(condición, valor_si_verdadero, valor_si_falso)

Múltiples Condiciones: case_when()

Para más de 2 categorías, usa case_when():

# Múltiples categorías de tamaño
vat_sized <- panel_vat %>%
  mutate(
    size_category = case_when(
      vat_outputs > 40000 ~ "Grande",
      vat_outputs > 20000 ~ "Mediano",
      vat_outputs > 5000 ~ "Pequeño",
      TRUE ~ "Micro"  # Todo lo demás
    )
  )

vat_sized %>%
  select(firm_id, vat_outputs, size_category) %>%
  head(5)
     firm_id vat_outputs size_category
      <char>       <int>        <char>
1: FIRM_0096       45914        Grande
2: FIRM_0081       29661       Mediano
3: FIRM_0024       10005       Pequeño
4: FIRM_0091       14410       Pequeño
5: FIRM_0014       33378       Mediano

Ejercicio 2: Práctica de Mutate

Puedes encontrar el ejercicio en la carpeta “Exercises/exercise_02_template.R”

10:00

Tus tareas:

Usando panel_vat:

  1. Crear net_vat (vat_outputs - vat_inputs)
  2. Crear vat_ratio (vat_inputs / vat_outputs)
  3. Crear bandera lógica is_refund (verdadero si net_vat < 0)
  4. Crear categoría compliance_status:
    • “Alto riesgo” si vat_ratio > 0.95
    • “Riesgo moderado” si vat_ratio > 0.80
    • “Bajo riesgo” en caso contrario

Bonus: Crear days_to_file calculando días entre declaration_date y el final de filing_quarter

Ejercicio 2: Soluciones

# Cargar paquetes
library(dplyr)
library(lubridate)

# Crear variables
vat_mejorado <- panel_vat %>%
  mutate(
    # 1. IVA neto
    net_vat = vat_outputs - vat_inputs,
    
    # 2. Ratio de IVA
    vat_ratio = vat_inputs / vat_outputs,
    
    # 3. Bandera de reembolso
    is_refund = if_else(net_vat < 0, TRUE, FALSE),
    
    # 4. Estado de cumplimiento
    compliance_status = case_when(
      vat_ratio > 0.95 ~ "Alto riesgo",
      vat_ratio > 0.80 ~ "Riesgo moderado",
      TRUE ~ "Bajo riesgo"
    )
  )

# Bonus: Días para presentar
vat_mejorado <- vat_mejorado %>%
  mutate(
    quarter_end = ceiling_date(declaration_date, "quarter") - days(1),
    days_to_file = as.numeric(declaration_date - quarter_end)
  )

# Verificar resultados
vat_mejorado %>%
  select(firm_id, net_vat, vat_ratio, is_refund, compliance_status) %>%
  head(5)

Ordenando Datos: arrange()

Ordenamiento Básico

arrange() ordena filas por columnas:

# Ordenar por vat_outputs (de menor a mayor)
vat_sorted <- panel_vat %>%
  arrange(vat_outputs)

vat_sorted %>%
  select(firm_id, vat_outputs) %>%
  head(5)
     firm_id vat_outputs
      <char>       <int>
1: FIRM_0066        1014
2: FIRM_0044        1045
3: FIRM_0020        1073
4: FIRM_0032        1110
5: FIRM_0072        1168

Ordenar descendente con desc():

# Mayores contribuyentes primero
vat_sorted_desc <- panel_vat %>%
  arrange(desc(vat_outputs))

vat_sorted_desc %>%
  select(firm_id, vat_outputs) %>%
  head(5)
     firm_id vat_outputs
      <char>       <int>
1: FIRM_0020       49969
2: FIRM_0096       49844
3: FIRM_0040       49806
4: FIRM_0075       49710
5: FIRM_0022       49689

Ordenamiento Múltiple

Ordenar por múltiples columnas:

# Ordenar por año, luego por empresa, luego por outputs
vat_multi_sorted <- panel_vat %>%
  arrange(filing_year, firm_id, desc(vat_outputs))

vat_multi_sorted %>%
  select(firm_id, filing_year, vat_outputs) %>%
  head(5)
     firm_id filing_year vat_outputs
      <char>       <int>       <int>
1: FIRM_0001        2021       24343
2: FIRM_0002        2021       26706
3: FIRM_0002        2021        3018
4: FIRM_0003        2021       29978
5: FIRM_0003        2021        7239

Tip

El orden importa! R ordena por la primera columna, luego desempata con la segunda, etc.

Resumen y Agrupación

Agregación Básica: summarize()

summarize() colapsa datos en resúmenes:

# Estadísticas generales
vat_summary <- panel_vat %>%
  summarize(
    total_vat = sum(vat_outputs, na.rm = TRUE),
    avg_vat = mean(vat_outputs, na.rm = TRUE),
    max_vat = max(vat_outputs, na.rm = TRUE),
    num_declarations = n()
  )

vat_summary
  total_vat  avg_vat max_vat num_declarations
1  25883247 25883.25   49969             1000

Funciones de resumen útiles:

  • sum() - total
  • mean() - promedio
  • median() - mediana
  • sd() - desviación estándar
  • min(), max() - mínimo, máximo
  • n() - contar filas
  • n_distinct() - contar valores únicos

Análisis por Grupo: group_by()

El verdadero poder viene de group_by() + summarize():

# Análisis por año
vat_by_year <- panel_vat %>%
  group_by(filing_year) %>%
  summarize(
    total_vat = sum(vat_outputs, na.rm = TRUE),
    avg_vat = mean(vat_outputs, na.rm = TRUE),
    num_firms = n_distinct(firm_id),
    .groups = "drop"
  )

vat_by_year
# A tibble: 3 × 4
  filing_year total_vat avg_vat num_firms
        <int>     <int>   <dbl>     <int>
1        2021   8582818  26088.        96
2        2022   8436159  25410.        95
3        2023   8864270  26148.        97

Important

Siempre agrega .groups = "drop" después de summarize para evitar problemas!

Agrupación Múltiple

Agrupar por múltiples variables:

# Análisis por año Y trimestre
vat_by_period <- panel_vat %>%
  group_by(filing_year, filing_quarter) %>%
  summarize(
    total_vat = sum(vat_outputs, na.rm = TRUE),
    num_declarations = n(),
    .groups = "drop"
  )

head(vat_by_period, 8)
# A tibble: 8 × 4
  filing_year filing_quarter total_vat num_declarations
        <int>          <int>     <int>            <int>
1        2021              1   1870290               72
2        2021              2   2127706               77
3        2021              3   2446393               95
4        2021              4   2138429               85
5        2022              1   2317221               90
6        2022              2   1925538               78
7        2022              3   2352286               86
8        2022              4   1841114               78

Conteo Simple: count()

Para solo contar, count() es más simple:

# Contar declaraciones por año
panel_vat %>%
  count(filing_year)
   filing_year     n
         <int> <int>
1:        2021   329
2:        2022   332
3:        2023   339

Con múltiples variables:

# Contar por año y trimestre
panel_vat %>%
  count(filing_year, filing_quarter)
    filing_year filing_quarter     n
          <int>          <int> <int>
 1:        2021              1    72
 2:        2021              2    77
 3:        2021              3    95
 4:        2021              4    85
 5:        2022              1    90
 6:        2022              2    78
 7:        2022              3    86
 8:        2022              4    78
 9:        2023              1    82
10:        2023              2    91
11:        2023              3    94
12:        2023              4    72

Mutaciones Agrupadas

group_by() también funciona con mutate():

# Calcular cuota de empresa del IVA trimestral
vat_with_share <- panel_vat %>%
  group_by(filing_quarter) %>%
  mutate(
    quarter_total = sum(vat_outputs, na.rm = TRUE),
    firm_share = vat_outputs / quarter_total * 100
  ) %>%
  ungroup()  # ¡Siempre desagrupar después!

vat_with_share %>%
  select(firm_id, filing_quarter, vat_outputs, firm_share) %>%
  head(5)
# A tibble: 5 × 4
  firm_id   filing_quarter vat_outputs firm_share
  <chr>              <int>       <int>      <dbl>
1 FIRM_0096              1       45914      0.697
2 FIRM_0081              2       29661      0.471
3 FIRM_0024              1       10005      0.152
4 FIRM_0091              3       14410      0.200
5 FIRM_0014              3       33378      0.464

Warning

Siempre usa ungroup() después de operaciones agrupadas con mutate!

Trabajando con Fechas

El Paquete lubridate

lubridate hace que trabajar con fechas sea fácil:

library(lubridate)

# Extraer componentes de fecha
fecha_ejemplo <- as.Date("2023-03-15")

year(fecha_ejemplo)    # Año
[1] 2023
month(fecha_ejemplo)   # Mes (número)
[1] 3
day(fecha_ejemplo)     # Día
[1] 15
quarter(fecha_ejemplo) # Trimestre
[1] 1
wday(fecha_ejemplo)    # Día de la semana (1 = Domingo)
[1] 4

Creando Variables de Fecha

Patrón común para datos tributarios:

# Agregar componentes de fecha útiles
vat_with_dates <- panel_vat %>%
  mutate(
    filing_year = year(declaration_date),
    filing_quarter = quarter(declaration_date),
    filing_month = month(declaration_date),
    filing_day = day(declaration_date),
    filing_weekday = wday(declaration_date)
  )

vat_with_dates %>%
  select(declaration_date, filing_year, filing_quarter, filing_month, filing_weekday) %>%
  head(3)
   declaration_date filing_year filing_quarter filing_month filing_weekday
             <Date>       <int>          <int>        <int>          <int>
1:       2023-01-31        2023              1            1              3
2:       2022-05-31        2022              2            5              3
3:       2023-03-31        2023              1            3              6

Cálculos de Fecha

Calcular diferencias de fecha:

# Días desde la última declaración por empresa
vat_with_gaps <- panel_vat %>%
  arrange(firm_id, declaration_date) %>%
  group_by(firm_id) %>%
  mutate(
    days_since_last = as.numeric(declaration_date - lag(declaration_date))
  ) %>%
  ungroup()

vat_with_gaps %>%
  select(firm_id, declaration_date, days_since_last) %>%
  filter(!is.na(days_since_last)) %>%
  head(5)
# A tibble: 5 × 3
  firm_id   declaration_date days_since_last
  <chr>     <date>                     <dbl>
1 FIRM_0001 2022-03-31                   335
2 FIRM_0001 2022-05-31                    61
3 FIRM_0001 2022-08-31                    92
4 FIRM_0001 2022-10-31                    61
5 FIRM_0001 2023-04-30                   181

Tip

lag() obtiene el valor de la fila anterior dentro de cada grupo!

Funciones de Fecha Útiles

# Redondear fechas
fecha_ejemplo <- as.Date("2023-03-15")

floor_date(fecha_ejemplo, "month")    # Inicio del mes
[1] "2023-03-01"
ceiling_date(fecha_ejemplo, "month")  # Final del mes
[1] "2023-04-01"
floor_date(fecha_ejemplo, "quarter")  # Inicio del trimestre
[1] "2023-01-01"

Operaciones de fecha comunes:

# Agregar/restar tiempo
fecha_ejemplo + days(7)      # 7 días después
fecha_ejemplo - months(1)    # 1 mes antes
fecha_ejemplo + years(1)     # 1 año después

# Calcular intervalos
interval(fecha_inicio, fecha_fin) / days(1)  # Días entre fechas

Operaciones Especiales

Removiendo Duplicados: distinct()

Obtener filas únicas:

# Obtener lista única de empresas
unique_firms <- panel_vat %>%
  distinct(firm_id)

nrow(unique_firms)
[1] 100

Mantener otras columnas:

# Obtener una declaración por empresa (la primera)
one_per_firm <- panel_vat %>%
  distinct(firm_id, .keep_all = TRUE)

nrow(one_per_firm)
[1] 100

Dividiendo Datos: slice()

Obtener filas específicas:

# Primeras 5 filas
panel_vat %>%
  slice(1:5) %>%
  select(firm_id, declaration_date)
     firm_id declaration_date
      <char>           <Date>
1: FIRM_0096       2023-01-31
2: FIRM_0081       2022-05-31
3: FIRM_0024       2023-03-31
4: FIRM_0091       2023-08-31
5: FIRM_0014       2023-09-30

Top/Bottom por grupo:

# Mayor declaración de IVA por empresa
top_per_firm <- panel_vat %>%
  group_by(firm_id) %>%
  slice_max(vat_outputs, n = 1) %>%
  ungroup()

head(top_per_firm, 3)
# A tibble: 3 × 8
  firm_id declaration_date vat_inputs vat_outputs reimbursement_date filing_year
  <chr>   <date>                <int>       <int> <date>                   <int>
1 FIRM_0… 2023-10-31             2032       49327 2022-01-31                2023
2 FIRM_0… 2023-07-31            42580       44400 2022-02-28                2023
3 FIRM_0… 2023-04-30            11753       47713 2022-09-30                2023
# ℹ 2 more variables: filing_quarter <int>, filing_month <int>

Muestreo: slice_sample()

Muestreo aleatorio para análisis:

# Muestra aleatoria de 5 filas
panel_vat %>%
  slice_sample(n = 5) %>%
  select(firm_id, vat_outputs)
     firm_id vat_outputs
      <char>       <int>
1: FIRM_0004       34890
2: FIRM_0003       33167
3: FIRM_0099       16159
4: FIRM_0029       41483
5: FIRM_0016       21110

Muestreo proporcional:

# Muestra aleatoria del 10%
panel_vat %>%
  slice_sample(prop = 0.1)

Reordenando Filas: relocate()

Mover columnas a posiciones específicas:

# Mover firm_id al principio
vat_reordered <- panel_vat %>%
  relocate(firm_id, declaration_date)

names(vat_reordered)[1:5]
[1] "firm_id"            "declaration_date"   "vat_inputs"        
[4] "vat_outputs"        "reimbursement_date"
# Mover columnas después de otra
panel_vat %>%
  relocate(vat_inputs, .after = vat_outputs)

# Mover columnas al final
panel_vat %>%
  relocate(filing_month, .after = last_col())

Construyendo Flujos de Trabajo Completos

Encadenando Múltiples Operaciones

El verdadero poder de dplyr viene de combinar operaciones en una secuencia lógica:

# Ejemplo de flujo de trabajo completo
analysis_result <- panel_vat %>%
  # Paso 1: Calcular nuevas variables
  mutate(
    net_vat = vat_outputs - vat_inputs,
    filing_quarter = quarter(declaration_date)
  ) %>%
  
  # Paso 2: Filtrar a datos recientes
  filter(filing_year == 2023) %>%
  
  # Paso 3: Analizar por trimestre
  group_by(filing_quarter) %>%
  summarize(
    total_vat = sum(net_vat, na.rm = TRUE),
    avg_vat = mean(net_vat, na.rm = TRUE),
    num_firms = n_distinct(firm_id),
    .groups = "drop"
  )

analysis_result
# A tibble: 4 × 4
  filing_quarter total_vat avg_vat num_firms
           <int>     <int>   <dbl>     <int>
1              1    442405   5395.        54
2              2     15185    167.        59
3              3   -104600  -1113.        62
4              4    179021   2486.        49

Cuándo Dividir en Pasos

A veces es mejor dividir pipelines largos en piezas más pequeñas:

Bueno para flujos de trabajo complejos:

# Paso 1: Agregar variables derivadas
vat_enhanced <- panel_vat %>%
  mutate(
    net_vat = vat_outputs - vat_inputs,
    filing_quarter = quarter(declaration_date)
  )

# Paso 2: Analizar
vat_summary <- vat_enhanced %>%
  group_by(filing_year, filing_quarter) %>%
  summarize(avg_vat = mean(net_vat, na.rm = TRUE), .groups = "drop")

head(vat_summary)
# A tibble: 6 × 3
  filing_year filing_quarter avg_vat
        <int>          <int>   <dbl>
1        2021              1   -519.
2        2021              2   2447.
3        2021              3    219.
4        2021              4    442.
5        2022              1    100.
6        2022              2  -1321.

Tip

Dividir en pasos cuando:

  • El pipeline se está volviendo demasiado largo (>10 operaciones)
  • Quieras verificar resultados intermedios
  • Reutilizarás conjuntos de datos intermedios

Creando Variables Derivadas

Construye tu análisis con columnas calculadas significativas:

# Crear un conjunto de datos enriquecido con muchas variables derivadas
panel_vat_enhanced <- panel_vat %>%
  mutate(
    # Cálculos financieros
    net_vat = vat_outputs - vat_inputs,
    vat_ratio = vat_inputs / vat_outputs,
    
    # Banderas de lógica de negocio
    is_refund = if_else(net_vat < 0, TRUE, FALSE),
    large_taxpayer = if_else(vat_outputs > 40000, TRUE, FALSE),
    high_ratio = if_else(vat_ratio > 0.9, TRUE, FALSE)
  )

# Verificar lo que creamos
panel_vat_enhanced %>%
  select(firm_id, net_vat, is_refund, large_taxpayer, high_ratio) %>%
  head(5)
     firm_id net_vat is_refund large_taxpayer high_ratio
      <char>   <int>    <lgcl>         <lgcl>     <lgcl>
1: FIRM_0096     652     FALSE           TRUE       TRUE
2: FIRM_0081   20436     FALSE          FALSE      FALSE
3: FIRM_0024   -5284      TRUE          FALSE       TRUE
4: FIRM_0091    5063     FALSE          FALSE      FALSE
5: FIRM_0014  -13939      TRUE          FALSE       TRUE

Guardando Salidas Transformadas

Guarda tus conjuntos de datos mejorados para usar en módulos posteriores:

# Guardar panel de IVA mejorado en carpeta Clean
panel_vat_clean <- panel_vat %>%
  mutate(
    net_vat = vat_outputs - vat_inputs,
    filing_quarter = quarter(declaration_date),
    is_refund = net_vat < 0,
    large_taxpayer = vat_outputs > 40000
  )

fwrite(panel_vat_clean,
       here("r_training_datax", "Exercises", "data", "Clean", "panel_vat_clean.csv"))

# Guardar panel de CIT mejorado en carpeta Clean
panel_cit_clean <- panel_cit %>%
  mutate(
    filing_quarter = quarter(declaration_date),
    effective_tax_rate = tax_paid / taxable_income
  )

fwrite(panel_cit_clean,
       here("r_training_datax", "Exercises", "data", "Clean", "panel_cit_clean.csv"))

Mejores Prácticas de Organización de Archivos

Mantén tus archivos organizados:

r_training_datax/
└── Exercises/
    └── data/
        ├── Raw/              # Datos originales, sin tocar
        │   ├── firm_characteristics.csv
        │   ├── vat_declarations.dta
        │   └── cit_declarations.xlsx
        ├── intermediate/     # Después de limpieza del Módulo 2
        │   ├── dt_firms.csv
        │   ├── panel_vat.csv
        │   └── panel_cit.csv
        └── Clean/            # Después de transformación del Módulo 3
            ├── panel_vat_clean.csv
            └── panel_cit_clean.csv

Tip

Guarda versiones mejoradas en la carpeta Clean ¡para que puedas usarlas en módulos futuros!

Ejercicio 3: Flujo de Trabajo de Transformación Completo

Puedes encontrar el ejercicio en la carpeta “Exercises/exercise_03_template.R”

15:00

Tus tareas:

Crea conjuntos de datos completamente transformados listos para análisis:

  1. Transformar panel_vat:
    • Agregar net_vat, filing_year, filing_quarter, filing_month
    • Calcular vat_ratio y days_since_last por empresa
    • Crear banderas: is_refund, large_taxpayer (>40000), high_ratio (>0.9)
    • Guardar como data/Clean/panel_vat_clean.csv usando fwrite()
  2. Transformar panel_cit:
    • Agregar filing_year, filing_quarter
    • Calcular effective_tax_rate (tax_paid / taxable_income)
    • Crear bandera: has_adjustments (adjustments != 0)
    • Guardar como data/Clean/panel_cit_clean.csv usando fwrite()
  3. Transformar dt_firms:
    • Renombrar columnas a minúsculas usando clean_names()
    • Guardar como data/Clean/dt_firms_clean.csv usando fwrite()
  4. Verificar tu trabajo:
    • Verificar que los tres archivos existan en la carpeta Clean usando file.exists()
    • Cargarlos de nuevo y verificar que las nuevas columnas estén presentes usando names() y glimpse()

Recuerda: ¡Estos conjuntos de datos limpios se usarán en los Módulos 4, 5 y 6!

Ejercicio 3: Soluciones

# Cargar paquetes requeridos
library(dplyr)
library(lubridate)
library(data.table)
library(here)
library(janitor)

# Cargar datos desde carpeta intermediate
panel_vat <- fread(here("r_training_datax", "Exercises", "data", "intermediate", "panel_vat.csv"))
panel_cit <- fread(here("r_training_datax", "Exercises", "data", "intermediate", "panel_cit.csv"))
dt_firms <- fread(here("r_training_datax", "Exercises", "data", "intermediate", "dt_firms.csv"))

# Convertir fechas
panel_vat$declaration_date <- as.Date(panel_vat$declaration_date)
panel_cit$declaration_date <- as.Date(panel_cit$declaration_date)

# 1. Transformar panel_vat
panel_vat_clean <- panel_vat %>%
  # Agregar componentes de fecha
  mutate(
    filing_year = year(declaration_date),
    filing_quarter = quarter(declaration_date),
    filing_month = month(declaration_date)
  ) %>%
  # Calcular métricas financieras
  mutate(
    net_vat = vat_outputs - vat_inputs,
    vat_ratio = vat_inputs / vat_outputs
  ) %>%
  # Crear banderas de negocio
  mutate(
    is_refund = if_else(net_vat < 0, TRUE, FALSE),
    large_taxpayer = if_else(vat_outputs > 40000, TRUE, FALSE),
    high_ratio = if_else(vat_ratio > 0.9, TRUE, FALSE, missing = FALSE)
  ) %>%
  # Calcular días entre declaraciones por empresa
  arrange(firm_id, declaration_date) %>%
  group_by(firm_id) %>%
  mutate(days_since_last = as.numeric(declaration_date - lag(declaration_date))) %>%
  ungroup()

# Guardar en carpeta Clean
fwrite(panel_vat_clean,
       here("r_training_datax", "Exercises", "data", "Clean", "panel_vat_clean.csv"))

# 2. Transformar panel_cit
panel_cit_clean <- panel_cit %>%
  # Agregar componentes de fecha
  mutate(
    filing_year = year(declaration_date),
    filing_quarter = quarter(declaration_date)
  ) %>%
  # Calcular métricas financieras
  mutate(
    effective_tax_rate = tax_paid / taxable_income
  ) %>%
  # Crear banderas de negocio
  mutate(
    has_adjustments = if_else(adjustments != 0, TRUE, FALSE)
  )

# Guardar en carpeta Clean
fwrite(panel_cit_clean,
       here("r_training_datax", "Exercises", "data", "Clean", "panel_cit_clean.csv"))

# 3. Transformar dt_firms
dt_firms_clean <- dt_firms %>%
  clean_names()

# Guardar en carpeta Clean
fwrite(dt_firms_clean,
       here("r_training_datax", "Exercises", "data", "Clean", "dt_firms_clean.csv"))

# 4. Verificar el trabajo
file.exists(here("r_training_datax", "Exercises", "data", "Clean", "panel_vat_clean.csv"))
file.exists(here("r_training_datax", "Exercises", "data", "Clean", "panel_cit_clean.csv"))
file.exists(here("r_training_datax", "Exercises", "data", "Clean", "dt_firms_clean.csv"))

# Cargarlos de nuevo
vat_verify <- fread(here("r_training_datax", "Exercises", "data", "Clean", "panel_vat_clean.csv"))
cit_verify <- fread(here("r_training_datax", "Exercises", "data", "Clean", "panel_cit_clean.csv"))
firms_verify <- fread(here("r_training_datax", "Exercises", "data", "Clean", "dt_firms_clean.csv"))

# Verificar columnas
names(vat_verify)
names(cit_verify)
names(firms_verify)

# Resumen rápido
glimpse(vat_verify)
glimpse(cit_verify)
glimpse(firms_verify)

Lo que Hemos Aprendido

Verbos centrales de dplyr:

  • filter() - seleccionar filas
  • select() - elegir columnas
  • mutate() - crear/modificar columnas
  • arrange() - ordenar datos
  • summarize() + group_by() - agregar
  • count() - frecuencias
  • distinct() - remover duplicados

Operaciones con fechas:

  • Analizar fechas con lubridate
  • Extraer componentes de fecha
  • Calcular diferencias de fecha
  • Crear variables basadas en tiempo

Resumen de Mejores Prácticas

Siempre usa pipes (%>%) para encadenar operaciones claramente

Guarda tu trabajo con <- para variables que usarás de nuevo

Incluye na.rm = TRUE en cálculos

Usa nombres de variables significativos (net_vat, no x1)

Comenta tu código para que otros lo entiendan

Guarda conjuntos de datos transformados en la carpeta Clean para módulos futuros

Agrega .groups = "drop" después de group_by() + summarize()

¡Gracias!

¿Preguntas?

Note

Próximos pasos:

  • Practica combinando múltiples operaciones dplyr
  • Experimenta con tus propios datos tributarios
  • ¡Prepárate para el Módulo 4: Combinando conjuntos de datos!