Unidad 1 - Práctica: del dato al KPI, del KPI al gráfico

Aplicación guiada en clase · Semana 4 · 06278-ECO

Autor/a

PhD. Eduard F. Martínez-González

1 Reglas de juego

Esta sesión asume que ya estudiaste la teoría

Aquí no volvemos a explicar qué hace filter(), qué es un KPI ni cómo se apilan las capas de un gráfico: eso quedó en el video (y su versión escrita interactiva) y en el quiz. Hoy esos verbos y capas se usan sobre los datos de un año completo de ventas. Si algo se te escapa, el glosario queda a un clic.

Lo que necesitas ahora mismo:

  • 💻 RStudio abierto dentro de tu proyecto intro_ba (semana 3).
  • 🌐 Internet (los datos se cargan desde la web del curso).
  • 🧑‍🤝‍🧑 Trabaja en tu computador, pero comenta cada checkpoint con tu vecino: si sus números no coinciden, uno de los dos tiene un hallazgo.

El escenario de hoy: eres el nuevo analista de una comercializadora de tecnología. La gerente quiere, antes de terminar el día, una tabla de KPIs y tres gráficos que respondan: ¿cómo nos fue en el año, por región, por vendedor y en el tiempo? Ese entregable — script reproducible incluido — es exactamente lo que vas a construir.

2 El setup profesional ≈ 10 min

Abre tu proyecto intro_ba (doble clic al .Rproj), crea un script nuevo y guárdalo en scripts/ como practica_semana4.R. Arranca con el encabezado estándar del curso:

## ============================================
## Práctica semana 4 — KPIs y gráficos
## Nombre: _______________
## Fecha:  _______________
## ============================================

## Librerías (el encabezado de todos nuestros scripts)
require(pacman)
p_load(dplyr, ggplot2)

## Cargar los datos del año desde la web del curso
ventas <- read.csv("https://eduard-martinez.github.io/databases/ba/ventas_2025.csv")

## Radiografía (reflejo de la semana 3)
str(ventas)
head(ventas)

Checkpoint 🎯: str() debe reportar 60 obs. de 9 variables: mes, trimestre, region, categoria, canal, vendedor, producto (texto), precio y cantidad (números). Cada fila es una transacción del año.

¿Error al cargar? Lee el mensaje. Si dice could not find function "p_load", te faltó require(pacman) (o instalar pacman: install.packages("pacman") en la consola). Si es de conexión, verifica el wifi y vuelve a intentar. Protocolo de la semana 3.

3 Los verbos, en modo pregunta-respuesta ≈ 15 min

Cada línea que sigue responde una pregunta de negocio. Escríbela, ejecútala y lee el resultado antes de pasar a la siguiente — el output es la respuesta.

##=== 1. Preguntas rápidas con verbos ===##

# ¿Cuántas ventas se hicieron por el canal Online?
ventas_online <- filter(ventas, canal == "Online")
nrow(ventas_online)

# ¿Cuáles fueron las ventas de la región Sur con precio mayor a 300?
filter(ventas, region == "Sur" & precio > 300)

# La gerente solo quiere ver 4 columnas, ordenadas de la venta
# más grande a la más pequeña (por precio):
ventas_red <- select(ventas, vendedor, producto, precio, cantidad)
arrange(ventas_red, desc(precio))

Checkpoint 🎯: Online tiene 30 transacciones (mitad exacta con el canal físico — dato curioso ya). Y arriba del ranking de precios debe aparecer un CRM de $580.

Ahora la variable que el negocio de verdad necesita — el ingreso — y una clasificación:

# Crear ingreso y etiquetar las ventas grandes
ventas <- ventas %>%
  mutate(ingreso = precio * cantidad,
         tamano  = ifelse(ingreso > 1000, "Grande", "Normal"))

# ¿Cuántas ventas "Grande" hubo? (pista de la semana 3: sum de una condición)
sum(ventas$tamano == "Grande")

Ojo a la jugada: esta vez sí sobrescribimos ventas (con ventas <- ventas %>% ...) porque el ingreso no es un experimento — es una columna que usaremos el resto de la sesión. Regla práctica: sobrescribe solo cuando la transformación es definitiva; si estás explorando, guarda en un objeto nuevo.

4 La tabla de KPIs ≈ 20 min

4.1 El pulso global

##=== 2. KPIs ===##

# ¿Cómo nos fue en el año, en tres números?
ventas %>%
  summarise(ingreso_total   = sum(ingreso),
            ticket_promedio = mean(ingreso),
            n_transacciones = n())

Checkpoint 🎯: ingreso total 53.035, ticket promedio ≈ 884, sobre 60 transacciones.

4.2 El desagregado que pidió la gerente

# KPIs por región, ordenados: LA tabla de la reunión
kpis_region <- ventas %>%
  group_by(region) %>%
  summarise(ingreso_total   = sum(ingreso),
            ticket_promedio = round(mean(ingreso)),
            n_transacciones = n(),
            .groups = "drop") %>%
  arrange(desc(ingreso_total))

kpis_region

Checkpoint 🎯: lidera Oeste (16.080) — y no porque venda más veces (tiene 14 transacciones, menos que Norte con 17), sino porque su ticket promedio (1.149) es por lejos el más alto. Lee la tabla con tu vecino: ¿ya ven por qué un solo KPI nunca cuenta la historia completa?

Ahora tú 🎯: replica la misma receta para construir kpis_vendedor (ingreso total y número de ventas por vendedor, ordenado). Una pista: solo cambia una palabra respecto al bloque anterior. (Verificación: María lidera con 14.285.)

# kpis_vendedor <- ventas %>% ...

4.3 Los atajos de exploración

# ¿Qué producto aparece en más transacciones?
count(ventas, producto, sort = TRUE)

# ¿Qué categoría tiene el mejor ticket promedio?
ventas %>%
  group_by(categoria) %>%
  summarise(ticket = round(mean(ingreso)), .groups = "drop") %>%
  arrange(desc(ticket))

Checkpoint 🎯: el más frecuente es el Antivirus (9 veces), pero el mejor ticket lo tiene Software (1.050). Frecuencia ≠ plata: segunda lección de KPIs del día.

Y como todo entregable serio, la tabla se exporta (a la carpeta output/ del proyecto — para eso la creamos):

write.csv(kpis_region, "output/kpis_region.csv", row.names = FALSE)

Verifica en el panel Files que output/ ya tiene tu primer producto analítico del día.

5 Los tres gráficos de la gerencia ≈ 30 min

Regla de la casa para cada gráfico: primero la pregunta, luego la tabla (si hace falta), luego el gráfico por capas, y por último una línea tuya de interpretación como comentario. Un gráfico = una idea.

5.1 Gráfico A — ¿Quién lidera? (comparar → barras)

##=== 3. Gráficos ===##

## A. Ingreso por región (la tabla kpis_region ya existe)
ggplot(kpis_region, aes(x = reorder(region, -ingreso_total), y = ingreso_total)) +
  geom_col(fill = "steelblue") +
  labs(title    = "Oeste lidera el ingreso del año",
       subtitle = "Con menos transacciones pero el ticket más alto",
       x = NULL, y = "Ingreso total ($)",
       caption  = "Fuente: ventas 2025, sistema interno") +
  theme_minimal()

# Interpretación (1 línea tuya): _______________________________________

Constrúyelo por capas de verdad: ejecuta primero solo la línea de ggplot(...), luego agrégale + geom_col(...), luego + labs(...). Ver el gráfico crecer una capa a la vez es la mejor vacuna contra el copy-paste ciego.

5.2 Gráfico B — ¿Vamos creciendo? (evolución → línea)

Pregunta con tiempo adentro → primero la tabla por trimestre, directo por el pipe hasta el gráfico:

## B. Ingreso por trimestre
ventas %>%
  group_by(trimestre) %>%
  summarise(ingreso_total = sum(ingreso), .groups = "drop") %>%
  ggplot(aes(x = trimestre, y = ingreso_total)) +
  geom_line(group = 1, color = "steelblue", linewidth = 1) +
  geom_point(size = 3, color = "steelblue") +
  labs(title = "El ingreso creció todos los trimestres",
       subtitle = "De 8.400 en Q1 a 17.545 en Q4 (más del doble)",
       x = NULL, y = "Ingreso total ($)") +
  theme_minimal()

# Interpretación (1 línea tuya): _______________________________________

Checkpoint 🎯: la línea debe subir sin descansos: 8.400 → 12.690 → 14.400 → 17.545. Nota el detalle profesional: el título no dice “ingreso por trimestre” — dice lo que el gráfico demuestra.

5.3 Gráfico C — ¿Precio y volumen se llevan mal? (relación → dispersión)

## C. Precio vs. cantidad, con la categoría como color
ggplot(ventas, aes(x = precio, y = cantidad, color = categoria)) +
  geom_point(size = 3, alpha = 0.7) +
  labs(title = "Lo barato se vende por volumen; lo caro, por unidad",
       x = "Precio unitario ($)", y = "Unidades por transacción",
       color = "Categoría") +
  theme_minimal()

# Interpretación (1 línea tuya): _______________________________________

Ahora tú 🎯 (el reto de la sesión): la gerente quiere un cuarto gráfico: “el ingreso total por vendedor, en barras horizontales, ordenado, y con cada barra de un color según el vendedor — sin leyenda, que el eje ya los nombra”. Tienes todas las piezas: kpis_vendedor + reorder() + fill = dentro de aes() + theme(legend.position = "none"). (Verificación: la barra más larga es María.)

6 Exportar: nada de capturas de pantalla ≈ 5 min

La regla del curso desde hoy: los gráficos se exportan con código, nunca con la tijera de recortes — así quedan en alta calidad y el proceso es reproducible. ggsave() guarda el último gráfico mostrado:

##=== 4. Exportar ===##
ggsave("output/grafico_region.png", width = 8, height = 5, dpi = 300)

Ejecuta de nuevo el Gráfico B y guárdalo como output/grafico_trimestre.png. Al final, tu carpeta output/ debe tener: 1 CSV y 2 PNG. Ese trío es el “producto mínimo” de un análisis descriptivo profesional.

7 Momento IA: itera un gráfico ≈ 8 min

Tu Gráfico A funciona, pero el eje Y muestra 16000 en vez de 16.000, y a la gerente le gustan los números con separador de miles. No sabes hacer eso (todavía) — situación perfecta para la IA, con las reglas de la semana 2:

  1. Pídelo con C-T-F-R. Por ejemplo: “[C] Estoy en un curso de analytics usando ggplot2 en R; este es mi código: (pega el Gráfico A). [T] Modifícalo para que el eje Y muestre separador de miles al estilo colombiano. [F] Devuélveme solo el código completo corregido, comentado. [R] No cambies nada más del gráfico; si necesitas un paquete extra, dime cuál y por qué.”
  2. Ejecuta lo que te devuelva. ¿Corre? ¿El eje quedó como querías?
  3. Si algo falla, itera: pega el error completo y pide la explicación (movimiento verificar de la semana 2).

Lo que acaba de pasar es el flujo real del analista moderno: tú pusiste la pregunta de negocio, la tabla y el gráfico base — la IA puso un detalle de sintaxis que no valía 20 minutos de Google. Tú validaste el resultado. Ese reparto de roles (criterio tuyo, sintaxis compartida) es el que evaluaremos todo el semestre — y se pone serio en la semana 8 con Claude Code.

8 Cierre: la prueba del gerente ≈ 7 min

Antes del taller, dos verificaciones:

1. La prueba de fuego técnica (semana 3): rm(list = ls()) en la consola → botón Source. Tu script debe reconstruir todo — tabla, gráficos y archivos en output/ — sin un solo error.

2. La prueba del gerente: mira tus tres gráficos e imagina que solo puedes mostrar uno en la junta directiva. Discute 2 minutos con tu vecino: ¿cuál elige cada uno y qué decisión de negocio soportaría? (¿Contratar otra “María”? ¿Replicar el modelo del Oeste? ¿Preparar inventario para un Q1 flojo?). No hay respuesta única — hay argumentos mejores que otros, y eso es exactamente lo que pide el proyecto final.


Siguiente parada → el Taller 4: la analítica de una cafetería — mismo flujo completo (datos → KPIs → gráficos → decisión), otro negocio, y esta vez sin guía.