Tema 04 - Análisis Exploratorio de Datos (AED)

Proceso para conocer y entender nuestros datos

Pedro Albarrán

Dpto. de Fundamentos del Análisis Económico. Universidad de Alicante

Alberto Pérez

Introducción al AED

De los datos en bruto a la información

  • El AED es una fase inicial importante, con dos objetivos:

    1. Conocer nuestros datos e identificar problemas → Preprocesamiento

      • qué variables, tipo de información, calidad (información faltante, inconsistencias, problemas en combinación de datos)
    2. Análisis descriptivo: identificar patrones y encontrar escenarios de análisis

  • NO hay una “receta”: el proceso es diferente con distintos datos o con los mismos datos para diferentes objetivos

    • Es un proceso iterativo para descubrir información

Caso de Estudio: PYMES Europeas

  • Una consultora analiza 500 PYMES europeas fundadas entre 1980-2020 para:

    • Evaluar salud financiera y solvencia
    • Identificar patrones de productividad
    • Analizar riesgo crediticio
    • Ofrecer recomendaciones de inversión
  • Fuente de datos: pymes_europa.csv

  • Objetivo del AED:

    • Limpiar y preprocesar los datos
    • Entender los datos (distribuciones y relaciones entre variables)
    • Descubrir patrones (riesgo de las empresa, diferencias por sector y país)

Primera Aproximación

Contexto y reconocimiento de los datos

  • Contexto: conocimiento previo de los datos (fuente, cómo están almacenados, etc.)

  • Cargar los datos

library(rio)
pymes <- import("data/pymes_europa.csv")
  • Reconocimiento inicial de las características: ¿todo como esperamos?

    • número de observaciones y de variables
    • tipo de cada variable
    • visualizar los datos
  • Consultar el “diccionario” de datos

    • Descripción de cada variable y unidades de medida
    • Tipo de variable esperado
diccionario <- read_csv("data/diccionario_pymes.csv")

Identificar Problemas de Calidad en los Datos

  1. Verificar que las variables la información y el tipo adecuado

    • Algunas variables deberían ser numéricas:
pymes <- pymes |>
  mutate( anio_fundacion = as.numeric(anio_fundacion),
          empleados = as.numeric(empleados),
          liquidez_ratio = as.numeric(liquidez_ratio)  )
  1. Detectar inconsistencias en texto, fechas, unidades, etc.

    • Ej.: en sector, “Tecnología”, “tecnologia”, “TECNOLOGÍA” son la misma categoría

    • este tipo de problemas se puede descubrir más adelante.

# Homogeneizar texto
pymes <- pymes |> 
  mutate( sector = str_to_lower(sector),
          sector = str_replace_all(sector, "tecnologia", "tecnología"),
          sector = str_replace_all(sector, "farmaceutico", "farmacéutico"),
          sector = str_replace_all(sector, "energia", "energía") )

Identificar Problemas (cont.)

  1. Las variables con información categórica deben ser factores
pymes <- pymes |>
  mutate(across(c(sector, pais, tipo_propiedad, tamano_ciudad), 
                ~parse_factor(.x))) |>
  mutate(rating_credito = factor(rating_credito, 
                           levels = c("AAA", "AA", "A", 
                                      "BBB", "BB", "B", 
                                      "CCC", "CC", "C", "D"),
                           ordered = TRUE)
  )
  1. Identificar Valores Faltantes (NAs)
pymes |> summary()

pymes |> 
  summarise(across(everything(), ~sum(is.na(.)))) |>
  pivot_longer(everything(), names_to = "variable", values_to = "NAs") |>
  filter(NAs > 0) |>
  arrange(desc(NAs))
  • Podríamos decidir borrar o reemplazar los NAs, pero se suele preferir decidir al modelizar

Identificar Problemas (y 3)

  1. Detectar y eliminar filas duplicadas
sum(duplicated(pymes))
pymes <- pymes |> distinct()
  1. Variables que contienen información redundante

    • Ej., activos_total y total_recursos son pasivos + patrimonio_neto (igualdad contable)
pymes <- pymes |> select(-total_recursos)
  1. Renombrar variables (para mayor claridad), generar nuevas

  2. ¿Mantenemos solo algunas variables u observaciones?

  3. Otras…

  • NO ES UNA RECETA: más adelante podemos volver atrás, para rehacer o tomar decisiones

Análisis de Variación (“univariante”)

Patrones de variación en los datos

  • Queremos entender cómo cambian los valores de una variable entre distintas observaciones (p. e., ventas de diferentes empresas), es decir, su distribución

    • diferentes técnicas según el tipo de variable (numérica o categórica).
  • Aspectos a observar en la distribución

    • Inconsistencias: categorías erróneas (“unknown”), valores fuera de rango

    • Concentración de valores: ceros, números redondos o repeticiones excesivas → ¿errores o patrones reales?

    • Categorías: ¿tienen sentido? ¿agrupar de manera diferente? ¿reagrupar si hay pocas observaciones?

    • Continuas: dispersión o asimetría (usar log?); ¿discretizar (ej. grupos de edad)?

    • Valores inusuales (“atípicos” o “outliers”): no encajan en el patrón general

      • ¿cambian los resultados del análisis sin ellos? ¿Qué los ha causado?

Variables Categóricas

  • Describimos la distribución con frecuencias y proporciones: con summary(), table(), mode() o con summarize(), count()
pymes |> count(sector, sort = TRUE) 

pymes |> count(sector, sort = TRUE) |> mutate(prop = n / sum(n))
  • Este análisis puede detectar situaciones donde queremos agrupar categorías:

    • dos clases similares
    • clases con pocas observaciones (análisis más difícil: visualizaciones desequilibradas, resultados poco confiables)
library(forcats)
pymes <- pymes |>
  mutate(sector_agrupado = fct_lump_min(sector, min = 15, 
                                  other_level = "Otros"), 
         sector_agrupado = fct_collapse(sector, 
                                  Grupo1 = c("manufactura", "textil"),
                                  Grupo2 = c("servicios", "comercio")))

Variables Categóricas: Visualización

  • Para distribuciones discretas, la mejor visualización de la distribución de los datos es un histograma.
# frecuencias absolutas
ggplot(data = pymes) + geom_bar(aes(x = tipo_propiedad))  
# frecuencias relativas (proporciones)
ggplot(data = pymes)+ geom_bar(aes(x = tipo_propiedad, 
                                   y = after_stat(prop), group = 1))

# Variantes
pymes |> count(tipo_propiedad) |> ggplot() + 
  geom_bar(aes(x = tipo_propiedad, y = n), stat = "identity")

ggplot(data = pymes) + geom_bar(aes(x = tipo_propiedad)) +
  theme(axis.text.x = element_text(angle = 90))

ggplot(data = pymes) + geom_bar(aes(x = tipo_propiedad)) +
  coord_flip()

# barra vertical
ggplot(data = pymes) + geom_bar(aes(x = "", fill = tipo_propiedad))
  • Observación: la mayor parte de las PYMEs son empresas familiares o S.L.

Variables Cuantitativas

  • Estadísticas descriptivas básicas con summary()
summary(pymes)
  • Información adicional con funciones para estadísticos (rango, varianza, cuartiles, asimetría)
summary(pymes$ingresos)
pymes |>
  summarise(
    media = mean(ingresos, na.rm = TRUE),
    mediana = median(ingresos, na.rm = TRUE),
    sd = sd(ingresos, na.rm = TRUE),
    min = min(ingresos, na.rm = TRUE),
    max = max(ingresos, na.rm = TRUE),
    q25 = quantile(ingresos, 0.25, na.rm = TRUE),
    q75 = quantile(ingresos, 0.75, na.rm = TRUE),
    NAs = sum(is.na(ingresos)))
  • Interés particular en amplia variabilidad, distribución asimétrica

Variables Cuantitativas: Visualización

  • Para distribuciones numéricas, la visualización de la distribución de los datos puede realizarse con un histograma, con la densidad o ambos.
ggplot(pymes) + geom_histogram(aes(x = empleados), bins = 30)
ggplot(pymes) + geom_density(aes(x = empleados))

ggplot(pymes, aes(x=empleados)) + 
  geom_histogram(aes(y=after_stat(density)), bins = 30) + 
  geom_density()
  • ¿Por qué hay acumulación en los últimos valores?
  • Probar varios anchos de intervalo (distintas formas de discretizar la variable continua de )

  • Si observamos una distribución muy asimétrica, considerar escala logarítmica

ggplot(pymes, aes(x = ingresos)) + geom_histogram(bins = 30) 
ggplot(pymes, aes(x = ingresos)) + geom_histogram(bins = 30) + 
  scale_x_log10()

Variables Cuantitativas: Visualización con Boxplots

  • Útiles para analizar dispersión, identificar outliers y comparar distribuciones
ggplot(pymes, aes(y = roe)) +
  geom_boxplot()
  • ¿A qué se deben los valores extremos?
    • Errores de medición → corregir o eliminar (ej. ¿es consistente el ROE = -31% con otras variables de la empresa?)
    • Casos reales extremos → mantener o analizar por separado (empresas excepcionales)

Herramientas Automáticas

  • datasummary_skim(): vista rápida de todas las variables (o algunas seleccionada), distinguiendo automáticamente por tipo

    • útil para uso personal, no necesariamente para incluir en informe final
library(modelsummary)
pymes |> datasummary_skim()
  • DataExplorer
library(DataExplorer)
plot_bar(pymes)        # para TODAS las variables categóricas
plot_histogram(pymes)  # para TODAS las variables numéricas

create_report(pymes)
  • dlookr ofrece heramientas para diagnóstico y exploración de datos
  • También podemos subir los datos a un chatbot de IA (ej., chatGPT) y pedir que haga en análisis exploratorio y limpieza

Análisis de Covariación (“multivariante”)

Análisis de Covariación

  • La covariación describe relaciones entre variables: tendencia a que los valores de una variable dependan de la otra

  • Estudiamos la distribución condicional de una variable \(\small{Y}\) dados los valores de otra \(\small{X}\)

    • Si \(\small{\Pr(Y|X=x_1) = \Pr(Y|X=x_0) = \Pr(Y) \Rightarrow}\) \(\small{Y}\) NO depende de \(\small{X}\)

      • p.e., el valor esperado de \(\small{Y}\) será el mismo para distintos valores de \(\small{X}\)
    • Si la probabilidad condicional de que \(\small{Y}\) tome valores altos (o bajos) depende de lo que sabemos de \(\small{X}\), se puede predecir (su valor esperado) a partir del valor de \(\small{X}\)

  • Punto de partida para formular modelos que explican patrones complejos de los datos

  • La forma de visualizar la posible existencia de relaciones depende del tipo de variables

Dos variables categóricas

  • Partimos de la distribución conjunta de frecuencias absolutas
pymes |> count(sector, rating) |>
  pivot_wider(names_from = rating, values_from = n)
  • PERO es más informativo la distribución condicional de frecuencias relativas

  • ¿Hay la misma proporción de los rating alto y bajo en distintos sectores?

datos <- pymes |> count(sector, rating) |> 
  group_by(sector) |> mutate(prop= n/sum(n)) |> select(-n) 
datos |> pivot_wider(names_from = sector, values_from = prop)      # tabla

datos |> ggplot() + geom_bar(aes(x=sector, y=prop, fill = rating), # gráfico
                      stat = "identity")

ggplot(pymes, aes(x = sector, fill = rating)) +                    # + directo
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent)
  • ¿Hay la misma distribución de sectores en distintos paises?
ggplot(pymes, aes(x = pais, fill = sector )) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent)

Dos variables numéricas

  • La forma obvia de visualizar relaciones entre variables continuas es un gráfico de dispersión; añadir smoothers ayuda a apreciar un patrón en los puntos
ggplot(pymes, aes(x = activos_total, y = ingresos)) +
  geom_point() + geom_smooth(method = "lm", se = TRUE) +
  scale_x_log10() +  scale_y_log10() 
  • Con GGally obtenemos una primera visión de conjunto

    • PERO la automatización no permite ajustes (ej., escala logarítmica)
library(GGally)
#pymes |> select(where(is.numeric)) |> ggpairs()
pymes |> select(empleados:ingresos) |> ggpairs()
  • Otra posibilidad: discretizar una variable continua y usar las técnicas anteriores
pymes |> mutate(empleados_group = cut(empleados, 
                                      breaks=seq(0, 250, by=25))) |>
  ggplot() + geom_boxplot(aes(y = ingresos, x = empleados_group)) + 
             scale_y_log10()

Dos variables numéricas: correlación

  • Podemos estimar modelos de regresión con dos variables continuas
summary(lm(data = pymes, ingresos ~ activos_total) )
  • Y también correlaciones para dos (o múltiples) variables
pymes |>
  select(activos_total, ingresos, empleados, 
         beneficio_neto, roe, roa) |>
  cor(use = "complete.obs")
  • O visualizar las correlaciones
datos <- pymes |>
  select(activos_total, pasivos, patrimonio_neto, ingresos, 
         ebitda, beneficio_neto, liquidez_ratio, roe, roa,
         deuda_patrimonio, empleados)

datos |> correlate() |> plot()

library(corrplot)
datos |> cor() |> corrplot()
datos |> cor() |> corrplot.mixed()

Una variable numérica y una categórica

  • ¿Es diferente la distribución de Y (continua) por categorías de X?

    • Cuidado: podemos necesitar escala logarítmica

    • También ajustes como reordenar las categorías de un factor (forcats), rotar los ejes, etc.

  • Podemos usar histogramas o densidades, en un mismo gráfico o con facetas

g0 <- ggplot(pymes, aes(x = ingresos)) +  scale_x_log10()
g0 + geom_density(aes(color = tamano_ciudad))
g0 + geom_density() + facet_wrap(~sector)
  • Con muchos grupos o uno muy pequeño, es difícil notar diferencias
pymes <- pymes |> mutate(rating = fct_collapse(rating_credito, 
                        "Rating Alto" = c("AAA", "AA", "A", "BBB"),
                        "Rating Bajo" = c("BB", "B", "CCC", "CC", "C", "D")))
ggplot(pymes, aes(x = ingresos, color = rating)) +     # color = rating_credito
            geom_density() + scale_x_log10()
  • También con gráficos de caja (menos información pero más fácil de comparar)

    • ¿cómo se vería este gráfico si no hubiesemos homogeneizado sector?
ggplot(pymes, aes(x = sector, y = ingresos, fill = sector)) +
  geom_boxplot() + scale_y_log10()

Una variable numérica y una categórica (cont.)

  • También podemos calcular estadísticos concretos de la distribución de Y para distintos valores de X
pymes |> group_by(sector) |>
  summarise(media = mean(ingresos, na.rm = TRUE),
            mediana = median(ingresos, na.rm = TRUE),
            n = n(),
            sd = sd(ingresos, na.rm = TRUE))
  • NOTA: una regresión simple equivale a calcular la media de la variable continua por grupos

\[ \scriptsize E[Y|X]=\beta_0+\beta_1 X \Rightarrow \begin{cases} E[Y|X=0] &=\beta_0 \\ E[Y|X=1]&=\beta_0+\beta_1 \end{cases} \]

lm(data = pymes, ingresos ~ sector) |> summary()
  • ¿Y mediante la correlación? NO tiene sentido cuando una variable es categórica
pymes |> select(ingresos, sector) |> cor()

Transformación: Motivación desde el AED

Crear Variables Derivadas

  • El AED puede sugerir creación de nuevas variables y transformación de otras (ej., logaritmos para variables con distribución asimétrica)
  • Discretizar (agrupar) variables continuas: la distribución de empleados tiene un rango muy amplio

    • Disyuntiva: Discretizar simplifica comunicación (Pequeña vs. Mediana) pero se pierde información (tratamos igual a 11 y 49 empleados)
pymes |> ggplot() + geom_histogram(aes(x = empleados))
pymes <- pymes |>
  mutate(tamano_empresa = cut(empleados, breaks = c(0, 10, 50, 250, Inf),
                 labels = c("Micro", "Pequeña", "Mediana", "Grande"),
                 include.lowest = TRUE) )
  • Agrupar categorías: la distribución de rating financiero mostró algunas categorías con pocas observaciones y otras con comportamiento similar

\(\Rightarrow\) Agrupar/Discretizar cuando:

  1. El análisis previo mostró que es necesario

  2. Tiene sentido de negocio

  1. Las categorías tienen comportamiento similar

  2. Mejora la robustez sin perder información crítica

Herramientas de AED Automatizado y uso de IA

La Promesa de la Automatización

  • El AED manualmente consume tiempo. Se pueden automatizar partes del proceso, pero con precaución

  • Ventajas de herramientas automatizadas: Velocidad, Exahaustividad, Primera Exploración

  • Limitaciones críticas:

    • Ruido: muchos gráficos irrelevantes

    • No entienden contexto de negocio

    • Interpretación superficial → No sugieren acciones específicas

  • Herramientas de AED Automatizado

    • Herramientas interactivas: GWalkR, explore, Radiant (también online)

    • Informes completos automatizados con DataExplorer, dlookr, smartEDA, DataMaid

create_report(pymes, y = ingresos)

IA Generativa para Análisis de Datos

  • El prompt efectivo es clave (no solo “analiza”)
Analiza pymes_europa.csv. Variables clave: ingresos, roe, sector, país. 
Contexto: PYMES europeas 2020-2024. ROE típico: 8-12%. 
Dame: limpieza, descriptivos, visualizaciones, análisis por sector
Pregunta: ¿Qué características tienen empresas con ROE > 15%?
  • Fortalezas
    • Código rápido y documentado
    • Sugiere análisis adicionales
  • Limitaciones críticas
    • No conoce el contexto (de negocio)
    • Análisis superficial
    • Riesgo de errores: inventar patrones inexistentes, interpretaciones incorrectas, confundir correlación con causalidad
    • Limitaciones técnicas: datos < 100-200MB, resultados dependen del prompt

Filosofía: Automatización Inteligente

  • Flujo recomendado
    1. Exploración rápida → automatización para empezar
    2. Identificar áreas de interés → ¿problemas? ¿relaciones/patrones? ¿sentido?
    3. Análisis profundo manual
      • Limpieza contextualizada
      • Visualizaciones específicas
      • Interpretación experta
    4. Uso de IA como asistente → generar código, sugerir análisis
    5. Validación crítica SIEMPRE → verifica código, valida decisiones, cuestiona recomendaciones
  • Reglas básicas
    • ❌ NO: Reportes automáticos , todas las visualizacion omo análisis final
    • ✓ SÍ: Automatización como punto de partida
    • ❌ NO: Confiar ciegamente en IA
    • ✓ SÍ: Validar críticamente todo
  • Regla de oro: La automatización acelera, el expertise guía. Nunca al revés.