Tema 02 - Visualización de datos

La Gramática de Gráficos para Análisis Económico

Pedro Albarrán

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

¿Por qué visualizar datos?

  • Resumir información que no se vería en los datos en bruto (hoja de cálculo)

  • Identificar patrones y relaciones entre variables

  • Comunicar hallazgos de forma efectiva a diferentes audiencias

  • La visualización es esencial en:

    • Empresas y consultoras: presentaciones ejecutivas con las conclusiones que salen de los datos
    • Bancos centrales y gobiernos: paneles de indicadores macroeconómicos
    • Medios: The Economist, Financial Times
    • Investigación económica
  • En un buen gráfico, la audiencia encuentra obvias las ideas a transmitir, sin abrumar con muchos hallazgos

ggplot2 y la Gramática de Gráficos

  • Componentes básicos:

    • Datos

    • Estéticas (aes): asocia variables a propiedades visuales (posición, longitud, área, color)

    • Geometrías (geom): objetos para representar datos (líneas, círculos, barras)

    • Escalas, Sistemas de coordenadas, Facetas (subgráficos), Contexto (títulos, leyendas), etc.

  • Construir gráficos como frases gramaticales

    • sujeto + verbo + objeto = oración

    • datos + geometría + estética = gráfico de ggplot2

“Por encima de todo, mostrar los datos”

Los datos del tema

  • Trabajaremos con una cadena de gimnasios y su entorno. Son tres conjuntos de datos, y cada uno responde a una pregunta distinta
library(ggplot2)
load("data/datosVisualizacion.RData")
  • ¿Quién es nuestra clientela y en qué se diferencia? clientes, una ficha por persona: lo que ingresa, lo que gasta, su edad, por qué canal compra y en qué segmento está

  • ¿Cómo va el negocio y de qué depende? ventas: cuánto se vendió y cuánto se invirtió en marketing, en cada región, producto y trimestre

  • ¿En qué entorno operamos? macro, un país por fila: renta, población, paro, inflación y deuda

  • De cada conjunto salen muchas preguntas, y cada una pide su propio gráfico

  • La descripción de cada variable está en su diccionario: clientes_info, ventas_info, macro_info

  • Los ficheros se descargan de la página Datos del curso, y van en un subdirectorio data dentro de vuestra carpeta del tema

Creando un “ggplot”

Un gráfico se construye en tres pasos. Cada pestaña añade uno:

ggplot() con los datos solos da un lienzo vacío: todavía no hemos dicho qué variable va a cada sitio.

ggplot(data = ventas)

La estética es la correspondencia entre una variable y una propiedad visual del gráfico. Se declara con aes(): aquí, qué variable va en cada eje. Ya hay ejes, pero aún no hay nada dibujado.

ggplot(data = ventas, aes(x = marketing, y = ventas))

El objeto geométrico es la forma que toman los datos: puntos, barras, líneas… Se añade como una capa más, con +.

ggplot(data = ventas, aes(x = marketing, y = ventas)) + 
  geom_point()

  • La estética y la geometría son las dos piezas que vemos a continuación

¿Dónde se pone la estética?

  • Si aes() va en ggplot(), la estética vale para todas las capas que vengan detrás. Si va dentro de un geom_, vale solo para esa capa

  • Con una sola capa, las dos formas dan el mismo gráfico:

ggplot(ventas,
       aes(marketing, ventas)) +
  geom_point()

ggplot(ventas) +
  geom_point(
    aes(marketing, ventas))

  • La diferencia aparece en cuanto hay más de una capa: lo declarado en ggplot() lo heredan todas, y así no hay que repetirlo

Objetos Geométricos

Cada geom_*() agrega un tipo diferente de capa:

Tipo Función Uso Habitual
Puntos geom_point() Dispersión
Líneas geom_line() Evolución temporal
Barras geom_bar() Frecuencias categóricas
Histograma geom_histogram() Distribución continua
Cajas geom_boxplot() Estadísticos descriptivos
Suavizado geom_smooth() Tendencias
Texto geom_text() Etiquetas

Para lista completa: buscar funciones que comienzan con geom_ en Ayuda

Asociación Estética, con aes()

  • Cada aes() es una asociación entre una señal visual y una variable:

    posición: x, y | forma: shape
    color: color exterior | relleno: fill (color interior)
    tamaño: size | tipo de línea: linetype
  • Algunas estéticas son solo adecuadas para variables cuantitativas o para cualitativas

  • Cada geom acepta solo un subconjunto de estéticas (ver ayuda)

  • Regla de oro: Si quieres que algo varíe con los datos, ponlo en aes()

ggplot(ventas, aes(x = marketing, y = ventas)) +
  geom_point(aes(color = region))

Asociación Estética vs. Opción Fija

Dentro de aes(): una variable se traduce en una señal visual, y aparece su leyenda

ggplot(ventas,
       aes(marketing, ventas)) +
  geom_point(
    aes(color = region))

Fuera de aes(): un valor fijo, igual para todos los puntos, sin leyenda

ggplot(ventas,
       aes(marketing, ventas)) +
  geom_point(
    color = "red")

  • Principio: cada señal visual debe representar información, no “embellecer”. Y no saturar: tres o cuatro variables a la vez no se leen
ggplot(macro, aes(y = desempleo, x = pib)) +        # demasiado
  geom_point(aes(size = inflacion, color = deuda))

PRÁCTICA en clase (1): ¿rojo o “rojo”?

Con el data frame clientes (300 fichas de la clientela de nuestra cadena de gimnasios):

  1. Dibujad la relación entre ingresos y gasto con geom_point()

  2. Pintad TODOS los puntos de rojo, de verdad (que no aparezca ninguna leyenda)

  3. Ahora ejecutad esto y describid qué veis: ¿de qué color salen los puntos? ¿qué dice la leyenda? ¿por qué?

    ggplot(clientes, aes(x = ingresos, y = gasto)) + geom_point(aes(color = "red"))

  4. Distinguid el segmento por color y el canal por forma. Y ahora añadid además size = edad. ¿Se lee el gráfico con tres variables encima? ¿Cuántas cosas a la vez puede leer quien lo mira?

  5. Añadid size = 4 dentro de aes() y luego fuera. Una de las dos no tiene sentido: ¿cuál y por qué? En una frase, ¿qué regla os sirve para decidirlo?

Nota

Esta práctica es el apartado a) del ejercicio 1: id haciéndola ahí, en vuestro .qmd.

Gráficos como Objetos

  • Un gráfico también es un objeto de R
graf_base <- ggplot(macro, aes(y = desempleo, x = pib)) +
                geom_point()
  • Se pueden agregar capas a este objeto:
graf_base + geom_line()
graf_base + geom_point(aes(shape = norte)) 
graf_base + geom_point(aes(size = inflacion, color = deuda))

Datos (y estéticas) específicas por capa

Ejemplo práctico:

  • geom_text(): acepta estéticas de etiquetas (variables con texto):
graf_base + geom_text(aes(label = pais), size = 3)

library(ggrepel)  # Evita solapamiento
graf_base + geom_text_repel(aes(label = pais), size = 3)
  • Ahora con datos específicos por capa si solo queremos señalar algunos puntos
graf_base + 
  geom_text_repel(
    data = subset(macro, 
                  pais %in% c("España","Francia","Alemania")), 
    aes(label = pais), size = 3)
  • Esta idea se puede generalizar: usar distintos datos o estéticas en cada capa según las necesidades del gráfico

Nota

Ahora el ejercicio 1, apartado b): etiquetar a quienes más gastan, con su propia capa de datos.

Gráficos que muestran datos transformados

  • Un gráfico de dispersión dibuja los datos tal cual. Otros calculan algo antes de dibujar, y conviene saber qué

geom_boxplot() no dibuja las observaciones: dibuja sus cuartiles y su mediana

ggplot(clientes,
       aes(y = gasto/1000)) +
  geom_boxplot()

geom_smooth() estima una regresión y dibuja la línea predicha, con su intervalo de confianza

graf_base + geom_smooth()
graf_base + geom_smooth(method = lm, se = FALSE)

Gráficos que muestran datos transformados (cont.)

  • geom_bar() y geom_histogram() convierten los datos en frecuencias

geom_bar() cuenta los casos de cada categoría: no hay que calcular nada antes. En Excel habría que haber contado primero

ggplot(ventas, aes(x = region)) + geom_bar()

En una variable continua no hay categorías naturales: los intervalos los elegimos nosotros, y esa elección cambia lo que se ve

graf <- ggplot(clientes, aes(x = ingresos/1000))
graf + geom_histogram(bins = 20)
graf + geom_histogram(binwidth = 3)
graf + geom_histogram(breaks = seq(10,90,5))

La misma información sin elegir intervalos, en frecuencia relativa

graf + geom_histogram(aes(y = after_stat(density)))
graf + geom_density()

PRÁCTICA en clase (2): el gráfico calcula por ti

Venís de Excel, donde para hacer un gráfico de barras hay que contar antes. Aquí no. Con clientes:

  1. Número de clientes de cada segmento, con geom_bar(). ¿Dónde está la tabla de frecuencias que habéis usado?

  2. Lo mismo, pero con la PROPORCIÓN que representa cada segmento, sin calcular nada aparte: el geom ya ha contado, y after_stat() deja usar lo que ha calculado

ggplot(clientes, aes(x = segmento, y = after_stat(prop), group = 1)) +
  geom_bar()
  1. En una frase: ¿qué significa que un geom “tiene una estadística por defecto”?

Nota

Esta práctica es el apartado c) del ejercicio 1.

PRÁCTICA en clase (3): distribuciones

  1. Distribución de los ingresos con geom_histogram(), probando bins = 10, bins = 40 y binwidth = 3. ¿Cuál de las tres le enseñaríais a dirección y por qué?

  2. Con una de las tres se ve un grupo de clientes de ingresos muy bajos y con las otras no. ¿Con cuál, y qué os dice eso sobre elegir los intervalos?

  3. Añadid un geom_boxplot() del gasto por segmento

Nota

Esta práctica es el apartado d) del ejercicio 1.

Escalas: Control de Asociación Estética

  • aes() establece qué variable asignar, la escala cómo representarla

  • Funciones de escala: scale_<estética>_<tipo>. Ejemplos,

Escala Tipos Ejemplos
scale_color_ identity scale_fill_continuous
scale_fill_ manual scale_color_discrete
scale_size_ continuous scale_color_manual
discrete scale_size_discrete
scale_shape_ discrete scale_shape_discrete
scale_linetype_ manual scale_shape_manual
identity scale_linetype_discrete
scale_x_ continuous scale_x_continuous
scale_y_ discrete scale_y_discrete
reverse scale_y_reverse
log10 scale_x_log10
date scale_x_date
datetime scale_y_datetime

Escalas (cont.)

  • Algunos argumentos son habituales en casi todas las escalas (name, breaks, labels)

  • Otros argumentos son específicos según el tipo de variables (continua, discreta) o la escala concreta

ggplot(macro, aes(y = pais, x = pib)) + 
  geom_point(aes(color = desempleo))  +
  scale_color_continuous(breaks = c(5, 10, 15),
                         labels = c("Bajo", "Medio", "Alto"), 
                         low = "green", high = "red")

ggplot(macro, aes(y = desempleo, x = pib/1000)) + 
  geom_point(aes(color = norte, size = deuda, shape = norte)) + 
  scale_y_continuous(breaks = seq(0, 20, 5), limits = c(-5, 25)) +
  scale_shape_discrete(labels = c("Norte", "Sur"), 
                       name = "Zona de Europa")
  • Nota: este ejemplo tiene elementos redundantes a efectos ilustrativos

Escala Logarítmica

  • En muchos contextos, las variables tienen un rango de valores amplio

    • PIB, población (Lux 0.6M vs ALE 83M), clientes (pyme 500 vs Inditex 200M)
  • Escala lineal vs logarítmica:

    • Lineal: misma distancia visual = mismo aumento absoluto → los valores pequeños quedan “aplastados” para mostrar los grandes

    • Logarítmica: misma distancia visual = mismo incremento relativo (%)

  • Aquí cambiamos a macro, un país por fila: la poblacion va de 1 a 138 millones, y es donde la escala logarítmica se nota. Con los ingresos de clientes no se vería nada, porque están todos en el mismo orden de magnitud

ggplot(macro, aes(y = desempleo, x = poblacion)) + 
  scale_x_log10(breaks = seq(0,100,20)) + geom_point()
  • Mejor que x = log(pib) porque los ejes se muestran en unidades originales
  • Usar logs cambia la interpretación de diferencias absolutas a porcentuales

    • Más relevante +10% o +500 clientes (mucho en pyme, nada en Inditex)

    • NO para “evitar” valores extremos o distribución asimétrica

PRÁCTICA en clase (4): la misma pregunta en dos escalas

Una consultora de inversión compara el perfil de ingresos de cinco grandes corporaciones y cinco startups. Los datos están en la página Datos del curso:

load("data/empresas.RData")
empresas_info      # qué es cada variable
  1. Diagrama de cajas de ingresos_millones por tipo, en escala normal

  2. El mismo gráfico con scale_y_log10()

  3. Comparando los dos: ¿qué diferencias hay en la posición central y en la variabilidad dentro de cada grupo? ¿Cuál de los dos gráficos es más informativo, y por qué?

  4. Si esa variabilidad mide el riesgo de una inversión, ¿dónde es más arriesgado invertir?

Nota

Esta práctica es el ejercicio 2, el de corporaciones y startups.

Facetas (sub-gráficos)

  • Los sub-gráficos por variables categóricas son una alternativa a aes() para añadir variables

  • Facilitan comparaciones, evitando la saturación visual (ej., demasiadas líneas en un solo gráfico)

graf_tiempo <- ggplot(ventas_tiempo, aes(x = fecha, y = ventas))
graf_tiempo + geom_line(aes(color = region))
  • facet_wrap(): facetas por una variable (usando “fórmula” ~)
graf_tiempo + geom_line() + facet_wrap(~region, ncol = 2)
  • facet_grid(): facetas en dos dimensiones
g3 <- ggplot(data = clientes) + geom_histogram(aes(x = gasto))
g3 + facet_grid(segmento ~ canal)  # Filas y columnas
g3 + facet_grid(segmento ~ .)      # Solo por filas 
g3 + facet_grid(. ~ canal)         # Solo por columnas

Contexto con labs()

  • Una buena práctica de legibilidad es dar título al gráfico, nombrar los ejes, incluir leyendas

    • Descripciones claras de variables y sus unidades
ggplot(macro, aes(y = desempleo, x = pib/1000)) + 
  geom_point(aes(color = norte, size = deuda)) + 
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relación entre PIB per cápita y tasa de desempleo",
    subtitle = "Países de la Unión Europea (2023)",
    caption = "Fuente: Eurostat",
    x = "PIB per cápita (miles de €)",
    y = "Tasa de desempleo (%)",
    color = "Norte",
    size = "Deuda pública (% PIB)") +
  scale_y_continuous(breaks = seq(0, 20, 5))

Otros Elementos de Contexto

  • annotate(): añade objetos geométricos NO asociados a variables:
ggplot(macro, aes(y = desempleo, x = pib/1000)) +
  geom_point(aes(color = norte)) + 
  geom_smooth(method = "lm", se = FALSE) +
  annotate("text", x = 60, y = 11, 
           label = "La doble división Norte-Sur") +
  annotate("text", x = 85, y = 6, label = "R ^ 2 == 0.45", 
           parse = TRUE)
  • Líneas de Referencia
ggplot(clientes, aes(x = canal, y = gasto/1000)) +
  geom_boxplot() +
  geom_hline(yintercept = 3.0, linetype = "dashed", 
             color = "red") +
  annotate("text", x = 3, y = 3.3, 
           label = "Objetivo mínimo", color = "red")

Personalizar el aspecto general

  • Se pueden cambiar manualmente colores (p.e., scale_fill_manual()) o la forma (ej., scale_shape_manual())

  • PERO es preferible usar paletas predefinidas con criterios de diseño y visualización de información:

graf <- ggplot(ventas, aes(x = region, y = ventas, fill = region)) + 
          geom_boxplot()
library(RColorBrewer)
display.brewer.all()
graf + scale_fill_brewer(palette = "Set2")
  • Se puede añadir una capa de tema (estilo general de todos los componentes)
graf + theme_gray()      
graf + theme_minimal()
  • También existen temas profesionales predefinidos en bibliotecas
library(ggthemes)
graf + theme_economist() + scale_fill_economist()     

Nota

Ahora el ejercicio 1, apartado e): tendencia, facetas, línea de referencia, labs() y temas.

Cierre: buenas prácticas

  • Buenas prácticas: visualizar no es decorar datos, es comunicar insights

    • Una idea por gráfico

    • Claridad sobre ornamentación: cada elemento visual debe tener propósito

    • Títulos y leyendas descriptivos e informativos

    • Evitar demasiados colores o patrones y la sobrecarga de información

Comentarios Finales

  • Guardar gráficos: en el panel Plots, con el botón Save Plot (en RStudio era Export), o con el comando
ggsave("analisis-ventas.pdf")
ggsave("dashboard-macro.png", width = 12, height = 8, dpi = 300)