Propósito: Este script toma la base cruda Base_Anonimizada_Caracterizacion.xlsx y produce una base limpia car_limpia.csv lista para unirse con ig_limpia.csv mediante el campo ID (UUID de empresa). Cada decisión está documentada.


0. Librerías y carga

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

1. Diagnóstico inicial

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)
Tabla 0. Diagnóstico inicial de la base de caracterización
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

2. Inicio del proceso de limpieza

car <- car_raw
n0  <- nrow(car)
cat("Empresas en la base original:", n0, "\n")
## Empresas en la base original: 910

3. Limpieza de Año de Inicio

# 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)
Años de inicio fuera del rango 1900-2026
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)
Estadísticas de Año de Inicio (valores válidos)
N Mínimo P25 Mediana Máximo
900 1978 2018 2021 2026

4. Limpieza de variables dicotómicas con typos

# 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:
car %>% count(`División de Finanzas`) %>% kable() %>% kable_styling(full_width=FALSE)
División de Finanzas n
No 412
No ’ 1
496
NA 1
car %>% count(RUT) %>% kable() %>% kable_styling(full_width=FALSE)
RUT n
No 229
678
si 1
NA 2
car %>% count(Presupuesto) %>% kable() %>% kable_styling(full_width=FALSE)
Presupuesto n
No 493
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:
car %>% count(`División de Finanzas`) %>% kable() %>% kable_styling(full_width=FALSE)
División de Finanzas n
No 413
496
NA 1
car %>% count(RUT) %>% kable() %>% kable_styling(full_width=FALSE)
RUT n
No 229
679
NA 2
car %>% count(Presupuesto) %>% kable() %>% kable_styling(full_width=FALSE)
Presupuesto n
No 494
410
NA 6

5. Estandarización de Género

# 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)
Tabla 5. Distribución de Género
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

6. Limpieza de Sector

# 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)
Tabla 6. Distribución de Sector (incluye NA)
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
cat("Empresas sin Sector:", sum(is.na(car$Sector)), "\n")
## Empresas sin Sector: 22
cat("Nota: Se conservan como NA. No se imputa sector.\n")
## Nota: Se conservan como NA. No se imputa sector.

7. Limpieza de Localidad

# "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)
Tabla 7. Distribución de Localidad
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

8. Limpieza de Herramientas de Pago (campo multirespuesta)

# "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)
Tabla 8. Número de herramientas de pago por empresa
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 %

9. Limpieza de Número de Empleados

# 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)
Tabla 9. Distribución de Número de Empleados
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)
Tabla 9b. Tamaño de empresa categorizado
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

10. Limpieza de Acceso a Financiamiento (simplificación)

# 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)
Tabla 10. Acceso a Financiamiento (etiqueta corta)
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

11. Parseo de fechas del sistema

# 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

12. Resumen del proceso de limpieza

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")
Tabla Final. Trazabilidad del proceso de limpieza — Caracterización
Paso Detalle
  1. Base cruda original
910 empresas, 37 columnas
  1. Años de inicio inválidos → NA
8 valores fuera de 1900-2026 corregidos a NA
  1. Typos en variables dicotómicas
División de Finanzas (1), RUT (1), Presupuesto (1)
  1. ‘Sin Localidad’ → NA
2 casos convertidos a NA
  1. Nuevas variables creadas
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

13. Exportar base limpia

# 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:
cat("  car_limpia.csv  —", nrow(car_limpia), "empresas |", ncol(car_limpia), "columnas\n")
##   car_limpia.csv  — 910 empresas | 44 columnas
cat("  car_limpia.xlsx —", nrow(car_limpia), "empresas |", ncol(car_limpia), "columnas\n")
##   car_limpia.xlsx — 910 empresas | 44 columnas
# Vista previa
glimpse(car_limpia)
## 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…

14. Verificación: compatibilidad con ig_limpia.csv

# 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

15. Checklist de calidad

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)
Checklist de calidad — Base de Caracterización limpia
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.