Propósito: Este script toma la base cruda
Base_Anonimizada_Caracterizacion.xlsxy produce una base limpiacar_limpia.csvlista para unirse conig_limpia.csvmediante el campoID(UUID de empresa). Cada decisión está documentada.
library(tidyverse)
library(readxl)
library(knitr)
library(kableExtra)
library(writexl)
library(lubridate)car_raw <- read_excel("Base_Anonimizada_Caracterizacion.xlsx",
sheet = "Caracterizacion")
cat("Base cruda:", nrow(car_raw), "empresas |", ncol(car_raw), "columnas\n")## Base cruda: 910 empresas | 37 columnas
tibble(
Columna = names(car_raw),
Tipo = sapply(car_raw, class),
N_nulos = sapply(car_raw, function(x) sum(is.na(x))),
Pct_nulo = round(sapply(car_raw, function(x) mean(is.na(x))) * 100, 1),
N_unicos = sapply(car_raw, function(x) n_distinct(x, na.rm = TRUE))
) %>%
kable(caption = "Tabla 0. Diagnóstico inicial de la base de caracterización") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = TRUE)| Columna | Tipo | N_nulos | Pct_nulo | N_unicos |
|---|---|---|---|---|
| ID | character | 0 | 0.0 | 910 |
| Descripción | character | 904 | 99.3 | 6 |
| Sector | character | 22 | 2.4 | 5 |
| Industria | character | 0 | 0.0 | 7 |
| Perfil_Digital | character | 2 | 0.2 | 2 |
| Puntos de Perfil | numeric | 2 | 0.2 | 7 |
| Ubicación | character | 1 | 0.1 | 2 |
| Localidad | character | 11 | 1.2 | 20 |
| Aglomeración SDDE | character | 597 | 65.6 | 13 |
| Programa Corazones Productivos | character | 11 | 1.2 | 2 |
| Región (Caracterización) | character | 0 | 0.0 | 1 |
| Año de Inicio | numeric | 2 | 0.2 | 41 |
| Número de Empleados | numeric | 4 | 0.4 | 17 |
| Razón de Inicio | character | 2 | 0.2 | 11 |
| Registro | character | 1 | 0.1 | 3 |
| RUT | character | 2 | 0.2 | 3 |
| Tipo de Registro | character | 137 | 15.1 | 4 |
| Seguridad Social | character | 1 | 0.1 | 4 |
| División de Finanzas | character | 1 | 0.1 | 3 |
| Presupuesto | character | 6 | 0.7 | 3 |
| Registro de Facturas | character | 346 | 38.0 | 21 |
| Acceso a Financiamiento | character | 0 | 0.0 | 6 |
| Software Financiero | character | 847 | 93.1 | 22 |
| Herramientas de Venta | character | 0 | 0.0 | 31 |
| Herramientas de Pago | character | 0 | 0.0 | 45 |
| ID ANIF | character | 827 | 90.9 | 83 |
| Consentimiento | character | 6 | 0.7 | 3 |
| Fecha de Creación | character | 0 | 0.0 | 893 |
| Fecha de Actualización | character | 0 | 0.0 | 679 |
| Edad | numeric | 838 | 92.1 | 36 |
| Genero | character | 32 | 3.5 | 3 |
| Educación | character | 33 | 3.6 | 9 |
| Registró_Ingresos_Gastos | character | 0 | 0.0 | 2 |
| Ratio_Uso_Pct | numeric | 0 | 0.0 | 103 |
| CV_Flujo_Neto_Quincenal | numeric | 739 | 81.2 | 148 |
| N_Quincenas_con_Datos_CV | numeric | 739 | 81.2 | 17 |
| Empresa_Activa_Uso_15pct | numeric | 0 | 0.0 | 2 |
## Empresas en la base original: 910
# Se identificaron 8 valores inválidos (fuera del rango 1900-2026):
# 2033, 8, 1012020, 209, 202, 20201, 5, 2109
# Estos corresponden a errores de digitación del usuario.
# Decisión: convertir a NA (no es posible inferir el año correcto).
cat("Valores inválidos en Año de Inicio (antes):\n")## Valores inválidos en Año de Inicio (antes):
car %>%
filter(!is.na(`Año de Inicio`)) %>%
mutate(ano_int = as.integer(`Año de Inicio`)) %>%
filter(ano_int < 1900 | ano_int > 2026) %>%
select(ID, `Año de Inicio`) %>%
kable(caption = "Años de inicio fuera del rango 1900-2026") %>%
kable_styling(full_width = FALSE)| ID | Año de Inicio |
|---|---|
| 05dfac53-279c-403e-8ca0-a58856380429 | 2033 |
| 3c538ab9-f5fd-4206-b25c-4c9f741d977c | 8 |
| 83927c04-7c70-4b34-ab2e-84948c6d803d | 1012020 |
| ac1a5bea-a43c-4d9e-b969-78db02a3e2ed | 209 |
| 57b80e1f-a4d1-4a63-8419-f0e9cc924c62 | 202 |
| c370f543-107a-4b1a-bdd8-7119e58db55c | 20201 |
| 1b3e0214-f389-46fd-83f9-c4df5f3c6cf2 | 5 |
| 716bc31e-7268-4fcb-b729-e765f98bb529 | 2109 |
car <- car %>%
mutate(
Ano_Inicio_limpio = case_when(
is.na(`Año de Inicio`) ~ NA_integer_,
as.integer(`Año de Inicio`) >= 1900 &
as.integer(`Año de Inicio`) <= 2026 ~ as.integer(`Año de Inicio`),
TRUE ~ NA_integer_
),
# Antigüedad en años (desde la fecha de corte del estudio)
antiguedad_anos = if_else(
!is.na(Ano_Inicio_limpio),
2026L - Ano_Inicio_limpio,
NA_integer_
)
)
n_anos_invalid <- sum(is.na(car$Ano_Inicio_limpio)) - sum(is.na(car_raw$`Año de Inicio`))
cat("\nAños inválidos convertidos a NA:", n_anos_invalid, "\n")##
## Años inválidos convertidos a NA: 8
car %>%
filter(!is.na(Ano_Inicio_limpio)) %>%
summarise(
N = n(),
Mínimo = min(Ano_Inicio_limpio),
P25 = quantile(Ano_Inicio_limpio, 0.25),
Mediana = median(Ano_Inicio_limpio),
Máximo = max(Ano_Inicio_limpio)
) %>%
kable(caption = "Estadísticas de Año de Inicio (valores válidos)") %>%
kable_styling(full_width = FALSE)| N | Mínimo | P25 | Mediana | Máximo |
|---|---|---|---|---|
| 900 | 1978 | 2018 | 2021 | 2026 |
# Las siguientes variables tienen typos puntuales documentados:
# - División de Finanzas: "No '" (1 caso) → "No"
# - RUT: "si" (1 caso) → "Sí"
# - Presupuesto: "no" (1 caso) → "No"
# Decisión: corregir los typos evidentes.
cat("Antes de corregir typos:\n")## Antes de corregir typos:
| División de Finanzas | n |
|---|---|
| No | 412 |
| No ’ | 1 |
| Sí | 496 |
| NA | 1 |
| RUT | n |
|---|---|
| No | 229 |
| Sí | 678 |
| si | 1 |
| NA | 2 |
| Presupuesto | n |
|---|---|
| No | 493 |
| Sí | 410 |
| no | 1 |
| NA | 6 |
car <- car %>%
mutate(
`División de Finanzas` = str_trim(`División de Finanzas`) %>%
recode("No '" = "No"),
RUT = str_trim(RUT) %>%
recode("si" = "Sí"),
Presupuesto = str_trim(Presupuesto) %>%
recode("no" = "No")
)
cat("\nDespués de corregir typos:\n")##
## Después de corregir typos:
| División de Finanzas | n |
|---|---|
| No | 413 |
| Sí | 496 |
| NA | 1 |
| RUT | n |
|---|---|
| No | 229 |
| Sí | 679 |
| NA | 2 |
| Presupuesto | n |
|---|---|
| No | 494 |
| Sí | 410 |
| NA | 6 |
# La columna se llama "Genero" (sin tilde) en la base.
# Verificar y estandarizar valores.
car %>%
count(Genero, sort = TRUE) %>%
mutate(Pct = round(n / sum(n) * 100, 1)) %>%
kable(caption = "Tabla 5. Distribución de Género") %>%
kable_styling(full_width = FALSE)| Genero | n | Pct |
|---|---|---|
| Mujer | 646 | 71.0 |
| Hombre | 230 | 25.3 |
| NA | 32 | 3.5 |
| Otro | 2 | 0.2 |
# Valores limpos — sin cambios necesarios en la escala de valores.
# Renombrar a "Género" para consistencia tipográfica.
car <- car %>% rename(Género = Genero)
cat("Columna renombrada: Genero → Género\n")## Columna renombrada: Genero → Género
# 22 empresas (2.4%) sin Sector asignado.
# No es posible imputar el sector sin información adicional.
# Decisión: conservar como NA y documentar.
car %>%
count(Sector, sort = TRUE) %>%
mutate(Pct = round(n / sum(n) * 100, 1)) %>%
kable(caption = "Tabla 6. Distribución de Sector (incluye NA)") %>%
kable_styling(full_width = FALSE)| Sector | n | Pct |
|---|---|---|
| Comercio | 671 | 73.7 |
| Servicios | 146 | 16.0 |
| Industria | 41 | 4.5 |
| NA | 22 | 2.4 |
| Agro | 16 | 1.8 |
| Otros | 14 | 1.5 |
## Empresas sin Sector: 22
## Nota: Se conservan como NA. No se imputa sector.
# "Sin Localidad" (2 casos) → convertir a NA para consistencia.
car <- car %>%
mutate(Localidad = if_else(Localidad == "Sin Localidad", NA_character_, Localidad))
car %>%
count(Localidad, sort = TRUE) %>%
mutate(Pct = round(n / sum(n) * 100, 1)) %>%
kable(caption = "Tabla 7. Distribución de Localidad") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Localidad | n | Pct |
|---|---|---|
| Suba | 134 | 14.7 |
| Engativá | 107 | 11.8 |
| Kennedy | 103 | 11.3 |
| Puente Aranda | 78 | 8.6 |
| Antonio Nariño | 66 | 7.3 |
| Ciudad Bolívar | 53 | 5.8 |
| Fontibón | 52 | 5.7 |
| Bosa | 49 | 5.4 |
| Usme | 42 | 4.6 |
| Barrios Unidos | 39 | 4.3 |
| Los Mártires | 30 | 3.3 |
| Usaquén | 26 | 2.9 |
| Rafael Uribe Uribe | 25 | 2.7 |
| Tunjuelito | 23 | 2.5 |
| Santa Fe | 17 | 1.9 |
| Teusaquillo | 16 | 1.8 |
| Chapinero | 15 | 1.6 |
| NA | 13 | 1.4 |
| San Cristóbal | 12 | 1.3 |
| La Candelaria | 10 | 1.1 |
# "Herramientas de Pago" es una pregunta de selección múltiple.
# Los valores están concatenados con coma "," o "||" como separadores.
# Estrategia: crear variables dummy (0/1) por cada opción + contar número de herramientas.
# Mapeo de los valores únicos al catálogo estándar:
HERRAMIENTAS_STD <- c(
"Efectivo",
"Billetera digital (Nequi/Daviplata)",
"Datáfono (Bold, Credibanco, Redeban, Wompi)",
"Códigos QR",
"Links de pago",
"Pasarelas de pago (tienda en línea)",
"Botones de pago (PSE)"
)
# Función para detectar cada herramienta (ignorando mayúsculas y separadores)
detectar_herramienta <- function(texto, patron) {
as.integer(!is.na(texto) & str_detect(str_to_lower(texto), patron))
}
car <- car %>%
mutate(
# Normalizar separadores antes de separar
herr_raw = str_replace_all(`Herramientas de Pago`, "\\|\\|", ","),
# Dummies por herramienta
herr_efectivo = detectar_herramienta(`Herramientas de Pago`, "efectivo"),
herr_billetera = detectar_herramienta(`Herramientas de Pago`,
"billetera|nequi|daviplata"),
herr_datafono = detectar_herramienta(`Herramientas de Pago`,
"datáfono|datafono|bold|credibanco|redeban|wompi"),
herr_qr = detectar_herramienta(`Herramientas de Pago`, "qr|código qr|codigo qr"),
herr_link_pago = detectar_herramienta(`Herramientas de Pago`, "link"),
herr_pasarela = detectar_herramienta(`Herramientas de Pago`, "pasarela"),
herr_pse = detectar_herramienta(`Herramientas de Pago`, "pse|botón"),
# Total de herramientas usadas
n_herramientas_pago = herr_efectivo + herr_billetera + herr_datafono +
herr_qr + herr_link_pago + herr_pasarela + herr_pse,
# Flag: usa alguna herramienta digital
usa_canal_digital = as.integer(herr_billetera | herr_qr | herr_link_pago |
herr_pasarela | herr_pse | herr_datafono)
) %>%
select(-herr_raw)
cat("Distribución de número de herramientas de pago:\n")## Distribución de número de herramientas de pago:
car %>%
count(n_herramientas_pago, sort = FALSE) %>%
mutate(Pct = round(n / sum(n) * 100, 1)) %>%
kable(caption = "Tabla 8. Número de herramientas de pago por empresa") %>%
kable_styling(full_width = FALSE)| n_herramientas_pago | n | Pct |
|---|---|---|
| 0 | 1 | 0.1 |
| 1 | 94 | 10.3 |
| 2 | 608 | 66.8 |
| 3 | 147 | 16.2 |
| 4 | 48 | 5.3 |
| 5 | 5 | 0.5 |
| 6 | 3 | 0.3 |
| 7 | 4 | 0.4 |
cat("\n% empresas que usan al menos un canal digital:",
round(100 * mean(car$usa_canal_digital, na.rm = TRUE), 1), "%\n")##
## % empresas que usan al menos un canal digital: 96.3 %
# Número de empleados es continuo. Se documenta la distribución.
# El valor "0" indica micronegocios sin empleados adicionales al dueño.
# No se imputan los 4 NA.
car %>%
filter(!is.na(`Número de Empleados`)) %>%
summarise(
N = n(),
Solo_dueno = sum(`Número de Empleados` == 0),
P50 = median(`Número de Empleados`),
P75 = quantile(`Número de Empleados`, 0.75),
P95 = quantile(`Número de Empleados`, 0.95),
Máximo = max(`Número de Empleados`)
) %>%
kable(caption = "Tabla 9. Distribución de Número de Empleados") %>%
kable_styling(full_width = FALSE)| N | Solo_dueno | P50 | P75 | P95 | Máximo |
|---|---|---|---|---|---|
| 906 | 413 | 1 | 2 | 4 | 60 |
# Crear variable de tamaño
car <- car %>%
mutate(
tamano_empresa = case_when(
is.na(`Número de Empleados`) ~ NA_character_,
`Número de Empleados` == 0 ~ "Unipersonal (solo el dueño)",
`Número de Empleados` <= 2 ~ "Microempresa pequeña (1-2 empleados)",
`Número de Empleados` <= 10 ~ "Microempresa mediana (3-10 empleados)",
TRUE ~ "Microempresa grande (>10 empleados)"
)
)
car %>%
count(tamano_empresa, sort = TRUE) %>%
mutate(Pct = round(n / sum(n) * 100, 1)) %>%
kable(caption = "Tabla 9b. Tamaño de empresa categorizado") %>%
kable_styling(full_width = FALSE)| tamano_empresa | n | Pct |
|---|---|---|
| Unipersonal (solo el dueño) | 413 | 45.4 |
| Microempresa pequeña (1-2 empleados) | 372 | 40.9 |
| Microempresa mediana (3-10 empleados) | 114 | 12.5 |
| Microempresa grande (>10 empleados) | 7 | 0.8 |
| NA | 4 | 0.4 |
# El campo tiene 6 categorías de texto largo. Se crea una versión corta.
FINANCIAMIENTO_CORTO <- c(
"No tengo historial crediticio" = "Sin historial",
"He accedido a créditos de bajo monto" = "Crédito bajo monto",
"No me interesa" = "No le interesa",
"He accedido a créditos de consumo" = "Crédito consumo",
"Tengo un historial crediticio negativo o estoy reportado" = "Historial negativo",
"He accedido a créditos productivos para mi negocio o créditos como persona jurídica" = "Crédito productivo"
)
car <- car %>%
mutate(
acceso_financiamiento_corto = recode(`Acceso a Financiamiento`,
!!!FINANCIAMIENTO_CORTO)
)
car %>%
count(acceso_financiamiento_corto, sort = TRUE) %>%
mutate(Pct = round(n / sum(n) * 100, 1)) %>%
kable(caption = "Tabla 10. Acceso a Financiamiento (etiqueta corta)") %>%
kable_styling(full_width = FALSE)| acceso_financiamiento_corto | n | Pct |
|---|---|---|
| Sin historial | 279 | 30.7 |
| Crédito bajo monto | 215 | 23.6 |
| No le interesa | 194 | 21.3 |
| Crédito consumo | 109 | 12.0 |
| Historial negativo | 88 | 9.7 |
| Crédito productivo | 25 | 2.7 |
# Las fechas de creación y actualización están en formato "d/m/y, H:M p. m."
# Se parsean igual que en limpieza_MDF.Rmd.
car <- car %>%
mutate(
fecha_creacion_car = parse_date_time(
`Fecha de Creación` %>%
str_replace_all("p\\. m\\.", "PM") %>%
str_replace_all("a\\. m\\.", "AM") %>%
str_trim(),
orders = "d/m/y, I:M p", quiet = TRUE
),
fecha_actualizacion_car = parse_date_time(
`Fecha de Actualización` %>%
str_replace_all("p\\. m\\.", "PM") %>%
str_replace_all("a\\. m\\.", "AM") %>%
str_trim(),
orders = "d/m/y, I:M p", quiet = TRUE
)
)
cat("Fechas de creación parseadas:", sum(!is.na(car$fecha_creacion_car)), "/", nrow(car), "\n")## Fechas de creación parseadas: 910 / 910
tibble(
Paso = c(
"1. Base cruda original",
"2. Años de inicio inválidos → NA",
"3. Typos en variables dicotómicas",
"4. 'Sin Localidad' → NA",
"5. Nuevas variables creadas",
" BASE LIMPIA FINAL"
),
Detalle = c(
paste(n0, "empresas, 37 columnas"),
"8 valores fuera de 1900-2026 corregidos a NA",
"División de Finanzas (1), RUT (1), Presupuesto (1)",
"2 casos convertidos a NA",
"Ano_Inicio_limpio, antiguedad_anos, tamano_empresa,\nacceso_financiamiento_corto, herr_* (7 dummies), n_herramientas_pago,\nusa_canal_digital, fecha_creacion_car, fecha_actualizacion_car",
paste(nrow(car), "empresas — sin eliminaciones")
)
) %>%
kable(caption = "Tabla Final. Trazabilidad del proceso de limpieza — Caracterización") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = TRUE) %>%
row_spec(6, bold = TRUE, background = "#D5F5E3")| Paso | Detalle |
|---|---|
|
910 empresas, 37 columnas |
|
8 valores fuera de 1900-2026 corregidos a NA |
|
División de Finanzas (1), RUT (1), Presupuesto (1) |
|
2 casos convertidos a NA |
|
Ano_Inicio_limpio, antiguedad_anos, tamano_empresa, acceso_financiamiento_corto, herr_* (7 dummies), n_herramientas_pago, usa_canal_digital, fecha_creacion_car, fecha_actualizacion_car |
| BASE LIMPIA FINAL | 910 empresas — sin eliminaciones |
# Seleccionar y ordenar columnas
car_limpia <- car %>%
select(
# Identificación
ID,
# Perfil de la empresa
Sector, Industria, Localidad,
`Aglomeración SDDE`, `Programa Corazones Productivos`,
Ano_Inicio_limpio, antiguedad_anos, tamano_empresa,
`Número de Empleados`,
# Perfil del empresario
Género, Educación, Edad,
# Perfil digital
Perfil_Digital, `Puntos de Perfil`,
# Formalización
Registro, RUT, `Tipo de Registro`, `Seguridad Social`,
# Gestión financiera
`División de Finanzas`, Presupuesto, `Registro de Facturas`,
`Software Financiero`,
# Acceso a financiamiento
`Acceso a Financiamiento`, acceso_financiamiento_corto,
# Herramientas de venta y pago
`Herramientas de Venta`, `Herramientas de Pago`,
herr_efectivo, herr_billetera, herr_datafono,
herr_qr, herr_link_pago, herr_pasarela, herr_pse,
n_herramientas_pago, usa_canal_digital,
# Variables de uso del programa (ANIF)
Ratio_Uso_Pct, Empresa_Activa_Uso_15pct,
CV_Flujo_Neto_Quincenal, N_Quincenas_con_Datos_CV,
Registró_Ingresos_Gastos,
# Fechas de sistema (auditoría)
fecha_creacion_car, fecha_actualizacion_car,
# ID alternativo
`ID ANIF`
) %>%
arrange(ID)
# Exportar
write_csv(car_limpia, "car_limpia.csv")
write_xlsx(car_limpia, "car_limpia.xlsx")
cat("Base limpia exportada:\n")## Base limpia exportada:
## car_limpia.csv — 910 empresas | 44 columnas
## car_limpia.xlsx — 910 empresas | 44 columnas
## Rows: 910
## Columns: 44
## $ ID <chr> "003451e3-734b-49aa-ac89-a3287e635ba5…
## $ Sector <chr> "Comercio", "Servicios", "Servicios",…
## $ Industria <chr> "Comercio", "Servicios", "Servicios",…
## $ Localidad <chr> "Kennedy", "Engativá", "Santa Fe", "P…
## $ `Aglomeración SDDE` <chr> NA, "La Estrada", NA, "Doce de Octubr…
## $ `Programa Corazones Productivos` <chr> "NO", "NO", "NO", "NO", "NO", "NO", "…
## $ Ano_Inicio_limpio <int> 2020, 2024, 2017, 2025, 2021, 2008, 2…
## $ antiguedad_anos <int> 6, 2, 9, 1, 5, 18, 5, 6, 6, 7, 4, 14,…
## $ tamano_empresa <chr> "Unipersonal (solo el dueño)", "Micro…
## $ `Número de Empleados` <dbl> 0, 1, 2, 1, 0, 0, 2, 2, 0, 1, 0, 5, 2…
## $ Género <chr> "Mujer", "Hombre", "Mujer", "Mujer", …
## $ Educación <chr> "Secundario completo", "Secundario co…
## $ Edad <dbl> NA, NA, NA, NA, NA, NA, NA, 46, 0, NA…
## $ Perfil_Digital <chr> "Tradicional", "En transformación dig…
## $ `Puntos de Perfil` <dbl> 5, 6, 6, 6, 4, 4, 5, 5, 7, 4, 5, 7, 6…
## $ Registro <chr> "No tiene registro", "Se encuentra in…
## $ RUT <chr> "No", "Sí", "Sí", "Sí", "Sí", "Sí", "…
## $ `Tipo de Registro` <chr> NA, "Persona Natural", "Persona Natur…
## $ `Seguridad Social` <chr> "No", "No", "Sí, de salud y pensión",…
## $ `División de Finanzas` <chr> "No", "Sí", "Sí", "Sí", "No", "No", "…
## $ Presupuesto <chr> "Sí", "Sí", "No", "No", "No", "No", "…
## $ `Registro de Facturas` <chr> NA, NA, NA, NA, NA, "Llevo el registr…
## $ `Software Financiero` <chr> NA, NA, NA, NA, NA, NA, NA, "no", "no…
## $ `Acceso a Financiamiento` <chr> "No tengo historial crediticio", "Ten…
## $ acceso_financiamiento_corto <chr> "Sin historial", "Historial negativo"…
## $ `Herramientas de Venta` <chr> "Usamos el voz a voz", "Usamos el voz…
## $ `Herramientas de Pago` <chr> "En efectivo,Transferencia a través d…
## $ herr_efectivo <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ herr_billetera <int> 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1…
## $ herr_datafono <int> 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0…
## $ herr_qr <int> 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0…
## $ herr_link_pago <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ herr_pasarela <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ herr_pse <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ n_herramientas_pago <int> 2, 2, 3, 2, 2, 1, 3, 2, 2, 3, 2, 3, 2…
## $ usa_canal_digital <int> 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1…
## $ Ratio_Uso_Pct <dbl> 0.0, 0.0, 0.0, 18.8, 0.0, 0.0, 14.3, …
## $ Empresa_Activa_Uso_15pct <dbl> 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0…
## $ CV_Flujo_Neto_Quincenal <dbl> NA, NA, NA, 4.24, NA, NA, NA, NA, 4.8…
## $ N_Quincenas_con_Datos_CV <dbl> NA, NA, NA, 3, NA, NA, NA, NA, 3, NA,…
## $ Registró_Ingresos_Gastos <chr> "No", "No", "No", "Sí", "No", "No", "…
## $ fecha_creacion_car <dttm> 2026-01-22 21:48:00, 2026-03-19 10:5…
## $ fecha_actualizacion_car <dttm> 2026-02-03 17:19:00, 2026-03-27 10:0…
## $ `ID ANIF` <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
# Esta sección verifica que car_limpia puede unirse con ig_limpia.csv
# usando el campo ID como llave.
# Ejecutar solo si ig_limpia.csv está disponible en el directorio de trabajo.
if (file.exists("ig_limpia.csv")) {
ig_limpia <- read_csv("ig_limpia.csv", show_col_types = FALSE)
ids_ig <- unique(ig_limpia$ID)
ids_car <- unique(car_limpia$ID)
cat("Empresas en ig_limpia:", length(ids_ig), "\n")
cat("Empresas en car_limpia:", length(ids_car), "\n")
cat("IDs presentes en ambas bases:", length(intersect(ids_ig, ids_car)), "\n")
cat("IDs en ig_limpia SIN perfil en car_limpia:", length(setdiff(ids_ig, ids_car)), "\n")
cat("IDs en car_limpia SIN transacciones en ig_limpia:", length(setdiff(ids_car, ids_ig)), "\n")
# El join
muestra_join <- ig_limpia %>%
left_join(car_limpia %>% select(ID, Sector, Género, Perfil_Digital,
Ano_Inicio_limpio, Localidad),
by = "ID") %>%
slice_head(n = 5)
cat("\nMuestra de join ig_limpia + car_limpia (5 filas):\n")
muestra_join %>%
select(ID, `Fecha de la transacción`, Tipo, Monto, Sector, Género) %>%
kable() %>%
kable_styling(full_width = FALSE)
} else {
cat("ig_limpia.csv no encontrado. Ejecute limpieza_MDF.Rmd primero.\n")
cat("El join se realiza con: left_join(ig_limpia, car_limpia, by = 'ID')\n")
}## Empresas en ig_limpia: 564
## Empresas en car_limpia: 910
## IDs presentes en ambas bases: 564
## IDs en ig_limpia SIN perfil en car_limpia: 0
## IDs en car_limpia SIN transacciones en ig_limpia: 346
##
## Muestra de join ig_limpia + car_limpia (5 filas):
| ID | Fecha de la transacción | Tipo | Monto | Sector | Género |
|---|---|---|---|---|---|
| 00a50a96-f845-418d-bc92-0791d6283817 | 2025-09-02 | Salida | 300000 | Comercio | Mujer |
| 00a50a96-f845-418d-bc92-0791d6283817 | 2025-12-10 | Salida | 31600 | Comercio | Mujer |
| 00a50a96-f845-418d-bc92-0791d6283817 | 2025-12-11 | Entrada | 100000 | Comercio | Mujer |
| 00a50a96-f845-418d-bc92-0791d6283817 | 2025-12-16 | Entrada | 79000 | Comercio | Mujer |
| 013e18cc-2d73-41fb-b3c5-c27e5e2d334c | 2026-04-28 | Entrada | 49000 | Comercio | Mujer |
tibble(
Verificación = c(
"Sin IDs duplicados",
"Año de Inicio: solo valores en rango 1900-2026 o NA",
"División de Finanzas: solo Sí / No / NA",
"RUT: solo Sí / No / NA",
"Presupuesto: solo Sí / No / NA",
"Localidad: sin 'Sin Localidad'",
"Columna Género disponible",
"Columna Ano_Inicio_limpio disponible",
"Columna tamano_empresa disponible",
"Dummies herr_* disponibles (7 columnas)",
"n_herramientas_pago disponible",
"acceso_financiamiento_corto disponible"
),
Resultado = c(
if_else(n_distinct(car_limpia$ID) == nrow(car_limpia),
"✅ OK — un ID por empresa", "❌ IDs DUPLICADOS"),
if_else(all(is.na(car_limpia$Ano_Inicio_limpio) |
(car_limpia$Ano_Inicio_limpio >= 1900 &
car_limpia$Ano_Inicio_limpio <= 2026)),
"✅ OK", "❌ AÑOS INVÁLIDOS"),
if_else(all(car_limpia$`División de Finanzas` %in% c("Sí", "No") |
is.na(car_limpia$`División de Finanzas`)),
"✅ OK", "❌ VALORES INESPERADOS"),
if_else(all(car_limpia$RUT %in% c("Sí", "No") | is.na(car_limpia$RUT)),
"✅ OK", "❌ VALORES INESPERADOS"),
if_else(all(car_limpia$Presupuesto %in% c("Sí", "No") |
is.na(car_limpia$Presupuesto)),
"✅ OK", "❌ VALORES INESPERADOS"),
if_else(!any(car_limpia$Localidad == "Sin Localidad", na.rm = TRUE),
"✅ OK", "❌ AÚN HAY 'Sin Localidad'"),
if_else("Género" %in% names(car_limpia), "✅ OK", "❌ FALTA"),
if_else("Ano_Inicio_limpio" %in% names(car_limpia), "✅ OK", "❌ FALTA"),
if_else("tamano_empresa" %in% names(car_limpia), "✅ OK", "❌ FALTA"),
if_else(all(c("herr_efectivo", "herr_billetera", "herr_datafono",
"herr_qr", "herr_link_pago", "herr_pasarela",
"herr_pse") %in% names(car_limpia)),
"✅ OK — 7 dummies", "❌ FALTAN DUMMIES"),
if_else("n_herramientas_pago" %in% names(car_limpia), "✅ OK", "❌ FALTA"),
if_else("acceso_financiamiento_corto" %in% names(car_limpia), "✅ OK", "❌ FALTA")
)
) %>%
kable(caption = "Checklist de calidad — Base de Caracterización limpia") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Verificación | Resultado |
|---|---|
| Sin IDs duplicados | ✅ OK — un ID por empresa |
| Año de Inicio: solo valores en rango 1900-2026 o NA | ✅ OK |
| División de Finanzas: solo Sí / No / NA | ✅ OK |
| RUT: solo Sí / No / NA | ✅ OK |
| Presupuesto: solo Sí / No / NA | ✅ OK |
| Localidad: sin ‘Sin Localidad’ | ✅ OK |
| Columna Género disponible | ✅ OK |
| Columna Ano_Inicio_limpio disponible | ✅ OK |
| Columna tamano_empresa disponible | ✅ OK |
| Dummies herr_* disponibles (7 columnas) | ✅ OK — 7 dummies |
| n_herramientas_pago disponible | ✅ OK |
| acceso_financiamiento_corto disponible | ✅ OK |
Siguiente paso: usar car_limpia.csv junto con
ig_limpia.csv en el análisis
analisis_MDF.Rmd. La llave de unión es el campo
ID (UUID de empresa), presente en ambas bases.
González Lozano, L.E. & Granados Rodríguez, H. (2026). Script de limpieza — Base de Caracterización Mi Diario Financiero. SDDE / ODEB.