dplyrCapacitación en R
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:
Al final de este módulo, podrás:
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
Note
¡Explicaremos qué significa %>% en un momento!
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.
El operador de asignación <- almacena resultados en un objeto:
[1] 211
Crea un NUEVO objeto cuando:
Sobrescribe el MISMO objeto cuando:
El operador de asignación <- tiene un atajo de teclado:
Tip
Alt + - (menos) (Windows/Linux)
Option + - (menos) (Mac)
¡Esto escribe <- automáticamente!
%>%El operador pipe (%>%) es la clave para escribir código claro y legible.
Piénsalo como “y luego”:
Cómo leerlo:
tax_data%>%) filtra a 2023%>%) selecciona columnas específicas%>%) ordena los resultadosTip
Atajo de teclado: Ctrl + Shift + M (Windows) o Cmd + Shift + M (Mac)
Entendamos los pipes con un ejemplo cotidiano:
Haciendo café (sin pipes):
Haciendo café (con pipes):
filter()filter() selecciona filas basándose en condiciones:
[1] 339
Operadores de comparación comunes:
== igual a!= no igual a> mayor que< menor que>= mayor o igual que<= menor o igual queUsar comas o & para AND (ambas condiciones deben ser verdaderas):
[1] 71
%in%Verificar si los valores coinciden con una lista:
character(0)
Puedes encontrar el ejercicio en la carpeta “Exercises/exercise_01_template.R”
10:00 Tus tareas:
Usando panel_vat:
vat_outputs > 30000Sugerencia: Para el bonus, usa group_by(), summarize(), arrange(), y head()
# 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)select()select() elige qué columnas mantener:
[1] "firm_id" "declaration_date" "vat_outputs" "vat_inputs"
Seleccionar columnas por patrón:
[1] "vat_inputs" "vat_outputs"
Puedes renombrar columnas dentro de select():
[1] "empresa" "fecha" "iva_cobrado" "iva_pagado"
mutate()mutate() es tu herramienta más importante - crea o modifica columnas:
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
Crear varias columnas a la vez:
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!
if_else()Crear columnas basadas en condiciones:
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
case_when()Para más de 2 categorías, usa case_when():
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
Puedes encontrar el ejercicio en la carpeta “Exercises/exercise_02_template.R”
10:00 Tus tareas:
Usando panel_vat:
net_vat (vat_outputs - vat_inputs)vat_ratio (vat_inputs / vat_outputs)is_refund (verdadero si net_vat < 0)compliance_status:
Bonus: Crear days_to_file calculando días entre declaration_date y el final de filing_quarter
# 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)arrange()arrange() ordena filas por columnas:
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():
Ordenar por múltiples columnas:
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.
summarize()summarize() colapsa datos en resúmenes:
total_vat avg_vat max_vat num_declarations
1 25883247 25883.25 49969 1000
Funciones de resumen útiles:
sum() - totalmean() - promediomedian() - medianasd() - desviación estándarmin(), max() - mínimo, máximon() - contar filasn_distinct() - contar valores únicosgroup_by()El verdadero poder viene de group_by() + summarize():
# 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!
Agrupar por múltiples variables:
# 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
count()Para solo contar, count() es más simple:
filing_year n
<int> <int>
1: 2021 329
2: 2022 332
3: 2023 339
Con múltiples variables:
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!
lubridate hace que trabajar con fechas sea fácil:
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
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!
[1] "2023-03-01"
[1] "2023-04-01"
[1] "2023-01-01"
distinct()Obtener filas únicas:
[1] 100
slice()Obtener filas específicas:
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:
# 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>
slice_sample()Muestreo aleatorio para análisis:
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
relocate()Mover columnas a posiciones específicas:
[1] "firm_id" "declaration_date" "vat_inputs"
[4] "vat_outputs" "reimbursement_date"
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
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:
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
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"))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!
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:
net_vat, filing_year, filing_quarter, filing_monthvat_ratio y days_since_last por empresais_refund, large_taxpayer (>40000), high_ratio (>0.9)data/Clean/panel_vat_clean.csv usando fwrite()filing_year, filing_quartereffective_tax_rate (tax_paid / taxable_income)has_adjustments (adjustments != 0)data/Clean/panel_cit_clean.csv usando fwrite()clean_names()data/Clean/dt_firms_clean.csv usando fwrite()file.exists()names() y glimpse()Recuerda: ¡Estos conjuntos de datos limpios se usarán en los Módulos 4, 5 y 6!
# 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)Verbos centrales de dplyr:
filter() - seleccionar filasselect() - elegir columnasmutate() - crear/modificar columnasarrange() - ordenar datossummarize() + group_by() - agregarcount() - frecuenciasdistinct() - remover duplicadosOperaciones con fechas:
lubridate✅ 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()
Note
Próximos pasos: