Unidad 1 - Manipulación y visualización de datos

Analítica para los negocios · Semana 4 · 06327-ECO

Autor/a

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

1 Cómo estudiar esta semana

La semana pasada aprendiste el idioma; esta semana lo pones a producir. El plan es un viaje completo: tomar una tabla de transacciones, transformarla hasta convertirla en una tabla de indicadores de negocio (KPIs), y luego comunicarla con gráficos que se entienden en tres segundos. Las dos herramientas son las más usadas de todo el ecosistema R: dplyr para manipular, ggplot2 para visualizar.

Tu ruta de esta semana (antes de llegar a clase)

  1. 🎬 Ve los dos videos de la semana — están embebidos aquí abajo: parte 1, el verbo a verbo de dplyr y parte 2, la construcción de gráficos por capas con ggplot2.
  2. 📖 Lee este documento ejecutando cada celda: es la versión escrita de los videos y, como la semana pasada, el código corre en tu navegador (panel 📦 Environment incluido, abajo a la derecha).
  3. Presenta el quiz de teoría en Intu.
  4. 💻 Ven a clase con RStudio funcionando y el proyecto intro_ba de la semana pasada a la mano.

Parte 1 — Transformación de datos con dplyr:

Parte 2 — Visualización con ggplot2:

El dataset de la semana

Trabajaremos con las ventas de una comercializadora de tecnología. En esta página los datos ya están precargados en dos versiones: ventas (9 transacciones, para aprender los verbos viendo todo) y ventas_full (36 transacciones, para que los gráficos tengan sustancia).

Si replicas desde RStudio, cárgalos desde internet:

require(pacman)
p_load(dplyr, ggplot2)

## La base pequeña (idéntica a la de esta página)
ventas <- read.csv("https://eduard-martinez.github.io/databases/ba/ventas.csv")

## Para la mitad de gráficos: usa la base del año completo como ventas_full
## (tiene más columnas y otros números — los patrones son los mismos)
ventas_full <- read.csv("https://eduard-martinez.github.io/databases/ba/ventas_2025.csv")
ventas_full <- mutate(ventas_full, ingreso = precio * cantidad)

2 Glosario de la semana

🔧 Verbo (dplyr)
Función que hace una transformación con nombre claro: filter() filtra filas, select() escoge columnas, mutate() crea variables, summarise() resume.
🔗 Pipe %>%
El conector "y luego": datos %>% filter(...) %>% summarise(...) encadena pasos sin crear objetos intermedios. Se lee de izquierda a derecha, como una receta.
📈 KPI
Key Performance Indicator: la cifra que resume el desempeño de algo — ingreso total, ticket promedio, número de transacciones. Es el producto típico de summarise().
🎯 Ticket promedio
El valor promedio de una transacción (ingreso total ÷ número de transacciones). KPI clásico del comercio: dice si vendes mucho de a poquito o poco de a mucho.
🧩 Granularidad
El nivel de detalle de un resumen: ¿una fila por todo el negocio, una por región, o una por región × trimestre? La define group_by().
🗺️ Mapeo estético (aes)
La conexión entre variables y atributos visuales: qué columna va al eje X, cuál al Y, cuál controla el color. Se declara dentro de aes().
📐 Geometría (geom)
La forma visual de los datos: barras (geom_col), puntos (geom_point), líneas (geom_line), histogramas (geom_histogram). Se elige según la pregunta.
🥞 Capa
Cada pieza que se suma a un gráfico con el operador +: la geometría, las etiquetas, el tema. Un gráfico de ggplot2 es una pila de capas.
🎨 Tema (theme)
El estilo visual del gráfico (fondo, grillas, tipografía): theme_minimal() para presentaciones, theme_bw() para reportes. No cambia los datos, solo el vestido.
🪟 Faceta
Panelitos que repiten el mismo gráfico para cada grupo (facet_wrap(~ region)). La alternativa elegante a amontonar todo en un solo gráfico.

3 El destino: una tabla de KPIs y sus gráficos

Antes de la herramienta, el propósito. Imagina que la gerente te pregunta: “¿cómo nos fue este año por región?”. La respuesta profesional no es reenviarle las 36 transacciones — es entregarle algo así:

region ingreso_total ticket_promedio n_transacciones
Norte
Sur
Centro

…y un gráfico donde la comparación se vea sola. Ese es el producto de esta semana: la tabla analítica de KPIs y 2-3 gráficos que la comunican. dplyr construye la tabla; ggplot2, los gráficos. Empecemos por conocer los datos:

Cada fila es una transacción: qué producto se vendió, a qué precio unitario, cuántas unidades, en qué región y trimestre. Datos limpios — sin faltantes ni errores. (El mundo real es más sucio; de eso nos ocuparemos en la semana 6.)

4 La gramática dplyr: un verbo a la vez

En la semana 3 filtraste con corchetes: ventas[ventas$region == "Norte", ]. Funciona, pero no se lee. dplyr propone algo mejor: verbos que dicen exactamente qué hacen. La lógica de trabajo es siempre la misma:

resultado <- verbo(datos, argumentos)

Se aplica el verbo, se guarda el resultado en un objeto nuevo, y el dataset original queda intacto.

4.1 select(): escoger columnas

ventas sigue completo en el Environment; ventas_red es una copia reducida. También puedes decir qué no quieres:

4.2 rename(): renombrar columnas

Sintaxis nuevo_nombre = nombre_viejo. Útil cuando los nombres originales son crípticos (x1, Var2) o traen espacios:

4.3 filter(): quedarse con las filas que importan

El verbo que más usarás en tu vida. Devuelve las filas que cumplen una condición:

Los operadores de comparación son los de la semana 3:

Operador Significado Ejemplo
== igual a region == "Norte"
!= diferente de region != "Sur"
> , >= mayor (o igual) que precio >= 150
< , <= menor (o igual) que cantidad < 5
%in% pertenece al conjunto region %in% c("Norte", "Sur")

Y las condiciones se combinan con & (ambas) y | (al menos una):

Advertencia

El error #1 de la semana: filter(ventas, region = "Norte") — con un solo = — falla. Dentro de filter() siempre se compara con ==. R incluso te lo sugiere en el mensaje de error; léelo.

4.4 arrange(): ordenar para leer mejor

El orden importa tanto como el contenido: un ranking se lee de arriba hacia abajo.

4.5 mutate(): crear variables nuevas

mutate() añade columnas calculadas — la materia prima de casi cualquier análisis. Nuestra tabla tiene precio y cantidad, pero la pregunta de negocio es sobre ingreso:

Puedes crear varias a la vez, y clasificar con ifelse(condición, si_cumple, si_no):

mutate() conserva las filas. Devuelve la misma cantidad de filas del original, con columnas de más. Guárdalo en la memoria porque su contraste con summarise() — que colapsa filas — es la pregunta favorita de los quices (y de los parciales).

4.6 Mini-ejercicio: cuatro preguntas, cuatro filtros

Escribe el código de cada una y verifica contra el resultado esperado:

Lo esencial de los verbos

  • select() columnas · filter() filas · rename() nombres · arrange() orden · mutate() variables nuevas.
  • Siempre: resultado <- verbo(datos, ...) — el original no se toca.
  • Comparar es ==; asignar argumentos es =.

5 Resúmenes: de la tabla al número

5.1 summarise(): colapsar en un indicador

Todos los verbos anteriores devuelven tablas del mismo largo (o más cortas). summarise() hace algo distinto: aplasta todas las filas en un resumen. Es la fábrica de KPIs.

Nueve filas entraron; salió una, con el nombre de columna que tú elegiste. Y puede calcular varios indicadores de una vez:

La función n() es especial: no recibe columna — simplemente cuenta las filas del grupo.

Tu caja de funciones de resumen

Centro: mean() (promedio), median() (mediana) · Dispersión: sd() (desviación estándar), min(), max() · Conteo: n() (filas), n_distinct() (valores únicos), sum() (total).

5.2 group_by() + summarise(): el dúo central del curso

Un resumen global responde “¿cómo nos fue?”. Pero la gerente preguntó “¿cómo nos fue por región?” — y comparar segmentos es el 80% de la analítica descriptiva. group_by() marca la tabla como agrupada; el siguiente summarise() calcula dentro de cada grupo:

Cada fila es una región. De un vistazo: quién genera más, quién tiene el ticket más alto, quién mueve más transacciones. El argumento .groups = "drop" desagrupa el resultado al final — inclúyelo siempre para evitar sorpresas en pasos posteriores.

Granularidad: ¿cuántas filas va a tener mi resumen?

Operación Resultado
summarise() sin agrupar 1 fila — el negocio completo
group_by(region) + summarise() 1 fila por región
group_by(region, categoria) + summarise() 1 fila por combinación región × categoría

Antes de ejecutar un resumen, predice cuántas filas saldrán. Si el resultado te sorprende, la granularidad no era la que creías.

De la tabla a la decisión. Esta tablita ya sostiene decisiones reales: ¿dónde invertir el presupuesto de mercadeo? ¿En qué región empujar el Software? La analítica descriptiva diagnostica; la decisión la toma el negocio — con tu tabla sobre la mesa.

5.3 Los atajos: count(), distinct(), n_distinct()

Regla mental: distinct() para ver los valores únicos, n_distinct() para contarlos, count() para frecuencias.

5.4 Mini-ejercicio: tu primera tabla de KPIs

6 El pipe %>%: “y luego”

Habrás notado el patrón: cada análisis crea objetos intermedios (ventas_ing, ventas_agr…) que solo existen para pasarle la posta al siguiente verbo. El operador pipe (%>%, viene con dplyr) elimina ese desfile: toma el resultado de la izquierda y lo mete como primer argumento de la función de la derecha. Se lee “y luego”:

Cuatro pasos, cero objetos intermedios, y el código se lee como una receta. Así escribiremos los análisis de aquí en adelante — y así los escribe la industria (y la IA, cuando le pidas código R).

Dos aclaraciones prácticas. (1) Verás también |>, el pipe “nativo” de R moderno: para este curso son equivalentes; usa el que prefieras y sé consistente. (2) El pipe no reemplaza el pensamiento por pasos: si un flujo se enreda, vuelve a los objetos intermedios, verifica cada uno, y re-encadena. Atajo de teclado: Ctrl/Cmd + Shift + M.

7 La gramática de gráficos

Tabla lista. Ahora hay que comunicarla — y aquí entra ggplot2, con una idea que lo cambia todo: un gráfico no se “elige de un menú” (al estilo Excel), se construye por capas, como una frase se construye con sujeto, verbo y complemento.

7.1 Los tres componentes mínimos

Todo gráfico necesita: datos (la tabla), mapeo estético (aes(): qué variable va a qué eje/color) y geometría (geom_*(): la forma visual). Las capas se conectan con +. Míralo crecer en tres pasos — para eso usaremos la base ampliada ventas_full (36 transacciones, ya con la columna ingreso):

Paso 0 — preparar la tabla (esto ya lo sabes hacer):

Paso 1 — los datos: el lienzo en blanco. R reserva el espacio, pero no sabe qué mostrar:

Paso 2 — el mapeo: aparecen los ejes. Ya sabe qué mostrar, no cómo:

Paso 3 — la geometría: aparece el gráfico.

Pieza Pregunta que responde
ggplot(data = ...) ¿Qué tabla grafico?
aes(x = ..., y = ...) ¿Qué variable va en cada eje?
geom_col() ¿Con qué forma la represento?

Ejercicio mental (hazlo antes de ejecutar): si en el código anterior cambias geom_col() por geom_point(), ¿qué esperas ver? Pruébalo en la celda. La lección: la estructura no cambia — solo la pieza de geometría. Aprendiste una gramática, no un gráfico.

7.2 Dentro vs. fuera de aes(): la confusión clásica

La regla: si el atributo visual depende de una variable de la tabla, va dentro de aes() (es información). Si es un valor fijo para todo el gráfico, va fuera (es decoración).

Regla práctica: si vas a escribir un valor entre comillas o un número literal ("steelblue", size = 3), casi seguro va fuera de aes().

8 La geometría según la pregunta

No hay gráfico “bonito” sin pregunta clara. Cada tipo de pregunta de negocio tiene su geometría natural.

8.1 Comparar categorías → geom_col()

“¿Qué región vendió más?” — barras. Dos mejoras que las vuelven profesionales: ordenarlas con reorder() y girarlas si los nombres son largos.

8.2 Ver una distribución → geom_histogram()

“¿Cómo se distribuyen los precios de lo que vendemos?” — el histograma parte el rango en cajones (bins) y cuenta cuántas transacciones caen en cada uno. Solo necesita x:

Se leen dos montañas: muchos productos baratos (Mouse, Soporte) y un grupo de caros (Laptop). Esa forma “bimodal” ya es un hallazgo: vendemos en dos ligas de precio. Cambia bins a 5 y a 20 en la celda — mira cómo el nivel de detalle cambia la historia.

8.3 Mostrar una relación → geom_point()

“¿Los productos caros generan más ingreso por transacción?” — cada punto es una transacción:

Y el tercer canal de información — el color — mete otra variable al gráfico:

Ahora se ve la estructura del negocio: Hardware (caro, ingresos altos por transacción) vs. Software (barato, volumen).

8.4 Seguir una tendencia → geom_line()

“¿El ingreso viene creciendo?” — primero la tabla (¡siempre primero la tabla!), luego la línea:

El detalle técnico: como el eje X es categórico (Q1, Q2, Q3), group = 1 le dice a R “conecta todos los puntos en una sola línea”. Y fíjate: dos geometrías apiladas (geom_line + geom_point) — capas, literalmente.

8.5 El mapa completo

La pregunta empieza por… Geometría
“¿Cuál categoría es mayor/menor…?” geom_col()
“¿Cómo se distribuye…?” geom_histogram()
“¿Existe relación entre X e Y…?” geom_point()
“¿Cómo ha cambiado en el tiempo…?” geom_line()

8.6 Ponte a prueba: ¿qué gráfico uso?

🎯 Elige la geometría · 5 preguntas de negocio
Truco: subraya el verbo de la pregunta — comparar, distribuir, relacionar, evolucionar — y la geometría se elige sola.

9 Pulir para comunicar

Un gráfico sin títulos es un dato sin mensaje. Las últimas capas convierten “un gráfico que corre” en “un gráfico que convence”.

9.1 Etiquetas con labs()

La regla de oro del título: escribe el mensaje, no la descripción. “Norte lidera el ingreso” informa; “Gráfico de ingresos por región” decora.

9.2 Temas: el vestido del gráfico

Guía rápida: theme_minimal() para presentaciones (limpio, moderno) · theme_bw() para reportes técnicos · theme_classic() para publicaciones sobrias. El fondo gris por defecto (theme_gray) — evítalo en entregas profesionales.

9.3 Colores con propósito

Ya sabes fijar un color (fuera de aes()) o mapearlo a una variable (dentro). El paso final es elegir los colores con scale_fill_manual():

Advertencia

Tres errores que delatan al aficionado

  1. Eje Y que no empieza en cero (en barras). La barra “el doble de alta” debe representar el doble de valor. Para líneas de tendencia, la regla se relaja.
  2. Veinte categorías en un gráfico de barras. Ilegible. Filtra el top 10, agrupa el resto en “Otros”, o usa tabla.
  3. Colores sin significado. Cinco barras de cinco colores “porque se ve alegre” = ruido. El color o informa una variable, o es uno solo.

10 Facetas: el mismo gráfico para cada grupo (opcional)

Cuando superponer grupos satura el gráfico, facet_wrap() crea un panel por grupo, con las mismas escalas (comparación justa):

Existe también facet_grid(filas ~ columnas) para cruzar dos variables. Considéralo tu carta elegante para el proyecto final: “la evolución de ventas… en un panel por región” suena a analista senior.

11 El producto de la semana, de principio a fin

Todo junto: de las 36 transacciones crudas a un entregable de gerencia — una tabla de KPIs y dos gráficos — en ~20 líneas legibles:

¿Notaste el truco del Gráfico B? La tabla entra directo al ggplot() por el pipe — dplyr y ggplot2 encajan como piezas de Lego (solo cambia el conector: %>% entre verbos, + entre capas).

Checklist antes de compartir cualquier gráfico

12 Los 5 errores de la semana

1. No guardar el resultado. filter(ventas, region == "Norte") muestra y olvida. Si lo necesitas después: ventas_norte <- filter(...).

2. Comparar con =. Dentro de filter(), siempre ==. El error unexpected '=' es este.

3. Usar una columna que aún no existe. summarise(ventas, total = sum(ingreso)) falla si nadie creó ingreso. Primero mutate(), luego el resumen (object 'ingreso' not found es la pista).

4. Creer que group_by() hace algo visible. Solo marca los grupos — la tabla sigue igual. El cálculo lo ejecuta el summarise() que viene después.

5. Confundir mutate() con summarise(). Mnemotecnia: Mutate Mantiene las filas (columna nueva para cada una); Summarise Sintetiza (colapsa todo en un resumen). ¿“Para cada transacción…”? → mutate. ¿“El total/promedio de…”? → summarise.

13 Lo esencial de la semana

Al terminar la teoría (video + este documento), debes poder:

En la aplicación guiada en clase construiremos el producto completo con datos reales del año, y en el taller evaluable harás la analítica de un negocio tú solo.

14 Preguntas de comprensión

1. Sin ejecutarlo: ¿en qué se diferencian estos dos análisis?

# Bloque A
ventas %>% filter(precio > 100) %>% count(region)

# Bloque B
ventas %>% count(region) %>% filter(n > 2)
Ver respuesta El orden de los verbos cambia la pregunta. A filtra primero las transacciones caras y luego cuenta por región: “¿cuántas ventas caras tiene cada región?”. B cuenta todas las transacciones por región y luego filtra el resumen: “¿qué regiones tienen más de 2 transacciones?”. Mismas funciones, preguntas distintas, resultados distintos.

2. mutate(ventas, ingreso = precio * cantidad) devuelve 9 filas. summarise(ventas, total = sum(precio)) devuelve 1. ¿Por qué, y cuál usarías para calcular el margen de cada transacción?

Ver respuesta mutate() calcula un valor para cada fila y conserva la tabla (9 → 9 con columna nueva); summarise() colapsa las filas en un indicador (9 → 1). Para el margen de cada transacción — un valor por fila — se usa mutate(). Para el margen total del negocio, summarise().

3. ¿Cuál de las dos opciones pinta los puntos rojos, y qué hace la otra?

# Opción A
ggplot(ventas, aes(x = precio, y = cantidad, color = "red")) + geom_point()

# Opción B
ggplot(ventas, aes(x = precio, y = cantidad)) + geom_point(color = "red")
Ver respuesta La B: el color fijo va fuera de aes(). En la A, "red" dentro de aes() se interpreta como una pseudo-variable constante: R asigna un color de su paleta por defecto (¡suele salir rosado/salmón!) y agrega una leyenda inútil que dice “red”. Es el error clásico de mapeo estético.

4. Tu tabla tiene 40 productos y te piden “un gráfico con las ventas de todos”. ¿Qué propones?

Ver respuesta Cuarenta barras son ilegibles. Opciones profesionales: (1) top 10 ordenado con reorder() + barras horizontales, mencionando qué % del total representa; (2) agrupar el resto en “Otros”; (3) si de verdad necesitan los 40 valores, una tabla ordenada comunica mejor que un gráfico. Parte del oficio es saber cuándo no graficar.

15 Material adicional