El módulo 10 terminó con una advertencia: al abrir Papyrus al mundo, la web empezó a generar datos. Cada venta que Marta registra, cada búsqueda que Júlia teclea, cada visita a una ficha de libro deja rastro. Y con el rastro llegaron las preguntas de Ana: ¿qué títulos se consultan mucho pero se compran poco?, ¿qué día de la semana vende más?, ¿cuánto stock conviene pedir de cara a Sant Jordi? Ninguna de esas preguntas se responde programando la tienda: se responden entendiendo sus números. Ese oficio se llama ciencia de datos, y este módulo te da sus tres herramientas fundamentales — NumPy, pandas y Matplotlib — más una primera mirada honesta al aprendizaje automático. Esta lección prepara el terreno: qué es (y qué no es) la ciencia de datos, cómo se trabaja, qué piezas forman el ecosistema y con qué dataset vamos a responder las preguntas de Ana.
Contenido
- Qué es la ciencia de datos (y qué no es)
- El flujo de trabajo: de la pregunta a la conclusión
- Los roles del oficio: analista, científico e ingeniero de datos
- El ecosistema PyData: qué pieza hace qué
- Jupyter Notebook: el entorno habitual del análisis
- El dataset del módulo:
ventas_2026.csv - Lo que ya sabes hacer:
statisticsy sus límites
Qué es la ciencia de datos (y qué no es)
La ciencia de datos es la disciplina de extraer conocimiento útil de los datos para responder preguntas y tomar decisiones. Combina tres ingredientes que, por separado, ya conoces o intuyes:
- Programación — para leer, transformar y automatizar. Es lo que llevas 10 módulos haciendo.
- Estadística — para resumir, comparar y no engañarse con el azar.
- Conocimiento del negocio — Ana sabe que Sant Jordi (23 de abril) es su pico anual; ningún algoritmo lo sabe si nadie se lo cuenta.
Igual de importante es lo que no es:
| Mito | Realidad |
|---|---|
| "Es hacer gráficos bonitos" | El gráfico es el final; el 80% del trabajo es conseguir y limpiar datos |
| "Es inteligencia artificial" | El ML es una herramienta más (la veremos en 11-05); la mayoría de preguntas se responden contando y agrupando bien |
| "Necesitas big data" | Papyrus tiene cientos de filas, no millones, y aun así hay decisiones valiosas que tomar |
| "Es magia predictiva" | Un modelo solo proyecta patrones del pasado; si el futuro cambia (una pandemia, una moda), el modelo no lo ve venir |
El flujo de trabajo: de la pregunta a la conclusión
Todo análisis serio recorre el mismo camino, y conviene tenerlo delante antes de escribir una línea de código. Con las preguntas de Papyrus como ejemplo:
flowchart LR
A["1. Pregunta<br>¿Cuánto stock pedir<br>para Sant Jordi?"] --> B["2. Datos<br>ventas_2026.csv<br>logs de la web (M10)"]
B --> C["3. Limpieza<br>filas corruptas,<br>duplicados, huecos"]
C --> D["4. Exploración<br>agrupar, resumir,<br>visualizar"]
D --> E["5. Conclusión o modelo<br>'pide ~220 unidades,<br>El Quijote el que más'"]
E -.->|nuevas preguntas| A
Fíjate en la flecha de vuelta: explorar los datos casi siempre genera preguntas nuevas ("¿por qué Fausto se consulta tanto y se vende tan poco?"), y el ciclo vuelve a empezar. No es una cadena de montaje: es un bucle.
El reparto del módulo sobre este flujo: la limpieza y exploración son territorio de pandas (11-03), la visualización de Matplotlib (11-04), el modelo de scikit-learn (11-05), y NumPy (11-02) es el motor numérico que sostiene a todos.
Los roles del oficio
"Ciencia de datos" es un paraguas. En una empresa real el trabajo se reparte en (al menos) tres perfiles; en Papyrus los tres son Ana con distintos sombreros:
| Rol | Pregunta típica | En Papyrus | Herramientas estrella |
|---|---|---|---|
| Analista de datos | ¿Qué pasó y por qué? | "¿Qué día vendemos más?" | pandas, SQL, Matplotlib |
| Científico de datos | ¿Qué pasará? ¿Qué decisión tomo? | "¿Cuántas unidades pedir en abril?" | pandas, scikit-learn, estadística |
| Ingeniero de datos | ¿Cómo llegan los datos limpios y a tiempo? | El script que consolida ventas de tienda y web cada noche | Python, pipelines (¡tus generadores de M8!), bases de datos |
Este módulo te da la base de los dos primeros roles; del tercero ya tienes más de lo que crees: leer CSV (M6), pipelines con generadores (M8) y una web que produce datos (M10) es ingeniería de datos a pequeña escala.
El ecosistema PyData
Todas estas piezas se instalan con pip en tu entorno virtual de M1 (pip install numpy pandas matplotlib scikit-learn). Cada una tiene un papel claro:
| Módulo | Rol en el flujo | Lección |
|---|---|---|
| NumPy | Arrays numéricos rápidos; el motor que todos los demás usan por debajo | 11-02 |
| pandas | Tablas (DataFrames): cargar, limpiar, agrupar, unir — el csv.DictReader de M6 con esteroides |
11-03 |
| Matplotlib | Gráficos: convertir números en historias que Ana entienda de un vistazo | 11-04 |
| scikit-learn | Aprendizaje automático: modelos que aprenden patrones del histórico | 11-05 |
| Jupyter | El entorno interactivo donde todo lo anterior se explora cómodamente | aquí mismo |
La dependencia entre ellas no es casual: pandas está construido sobre NumPy, Matplotlib dibuja arrays de NumPy, y scikit-learn espera arrays de NumPy o DataFrames de pandas como entrada. Por eso el módulo empieza por NumPy aunque en el día a día escribas sobre todo pandas.
Jupyter Notebook, brevemente
El análisis de datos es conversacional: pruebas algo, miras el resultado, ajustas, repites. Los notebooks están hechos para eso: documentos vivos con celdas de código que se ejecutan una a una, intercaladas con texto y gráficos que quedan guardados junto al código.
Dentro, cada celda se ejecuta con Shift+Enter y su resultado aparece debajo — la última expresión de la celda se muestra sola, sin print(). ¿Cuándo usar cada formato?
| Situación | Notebook (.ipynb) |
Script (.py) |
|---|---|---|
| Explorar datos, probar hipótesis | Ideal | Incómodo (relanzar todo cada vez) |
| Informe con código, texto y gráficos | Ideal | No aplica |
Código de producción (la web de M10, el paquete papyrus) |
Mala idea | Ideal |
| Tests (M9), control de versiones limpio | Difícil de testear y de diffear | Ideal |
| Ejecutar cada noche automatizado | Posible pero forzado | Ideal |
Todo el código de este módulo funciona igual en un script .py — si prefieres seguir con tu editor de siempre, adelante. El notebook es una comodidad, no un requisito. La única diferencia práctica: en un script, para ver un DataFrame tendrás que envolverlo en print().
El dataset del módulo: ventas_2026.csv
En M6 creaste datos/ventas.csv (columnas fecha,titulo,importe). Desde M10, además, la web registra sus propias ventas. Ana ha consolidado ambos orígenes — el trabajo de ingeniero de datos de la tabla anterior — en un único fichero que usaremos todo el módulo: datos/ventas_2026.csv, con las ventas de enero a junio de 2026.
| Columna | Tipo | Significado |
|---|---|---|
fecha |
fecha yyyy-mm-dd |
Día de la venta |
titulo |
texto | Uno de los 4 títulos del catálogo |
unidades |
entero | Ejemplares vendidos en esa operación |
importe |
decimal | Total cobrado (si el cliente es socio, aplica la tarifa de socio de M3) |
canal |
texto | tienda (caja física) o web (la tienda de M10) |
Así empieza el fichero (que tiene 487 filas en total):
fecha,titulo,unidades,importe,canal
2026-01-02,La Odisea,1,12.50,tienda
2026-01-02,Hamlet,2,19.90,web
2026-01-03,El Quijote,1,15.71,tienda
2026-01-03,Fausto,1,21.00,web
2026-01-05,El Quijote,2,31.80,tienda
...
2026-04-23,El Quijote,3,47.70,tienda
2026-04-23,La Odisea,2,25.00,web
...Dos detalles que ya puedes leer con lo aprendido: la fila del 3 de enero cobra 15.71 por El Quijote — la tarifa de socio que calculaste en M3 (15.90 con IVA del 4 % y descuento de socio del 5 %: 15.90 * 1.04 * 0.95 ≈ 15.71) — y las filas del 23 de abril se acumulan sospechosamente: es Sant Jordi.
Lo que ya sabes hacer: statistics y sus límites
Antes de instalar nada nuevo, seamos justos con la biblioteca estándar. Con csv.DictReader (M6) y el módulo statistics (M3) ya puedes responder preguntas sencillas:
import csv
import statistics
from collections import Counter
from pathlib import Path
importes = []
titulos = []
with open(Path("datos") / "ventas_2026.csv", encoding="utf-8", newline="") as f:
for fila in csv.DictReader(f):
importes.append(float(fila["importe"]))
titulos.append(fila["titulo"])
print(f"Ventas registradas: {len(importes)}")
print(f"Importe medio: {statistics.mean(importes):.2f} €")
print(f"Importe mediano: {statistics.median(importes):.2f} €")
print(f"Título más frecuente: {Counter(titulos).most_common(1)}")Ventas registradas: 487
Importe medio: 15.03 €
Importe mediano: 12.50 €
Título más frecuente: [('El Quijote', 168)]Ya hay una lección estadística aquí: la media (15.03 €) es mayor que la mediana (12.50 €). Unas pocas ventas grandes (packs de Fausto a 21 € o el aluvión de Sant Jordi) tiran de la media hacia arriba; la mediana — el valor central — resiste mejor esos extremos. Cuando alguien te dé "el promedio", pregunta siempre cuál de los dos es.
Ahora los límites. Intenta responder "¿qué día de la semana vende más?" con la stdlib:
from datetime import date
por_dia = Counter()
with open(Path("datos") / "ventas_2026.csv", encoding="utf-8", newline="") as f:
for fila in csv.DictReader(f):
dia = date.fromisoformat(fila["fecha"]).weekday() # 0=lunes ... 6=domingo
por_dia[dia] += int(fila["unidades"])
print(por_dia)Funciona — y en 11-03 comprobaremos que da sábado como ganador. Pero fíjate en el coste: conversión de tipos a mano en cada fila, un Counter por cada pregunta, y si ahora quieres "unidades por día de la semana y por canal, solo de socios, ordenado" el código crece en bucles anidados. Y todo es texto: "12.50" no se puede sumar hasta que tú lo conviertas, fila a fila. La ciencia de datos hace estas preguntas por docenas; necesitas herramientas donde cada pregunta cueste una línea, no un bucle. Eso son NumPy y pandas.
Errores Comunes y Consejos
- Saltarse la pregunta e ir directo al código. El error número uno. "Analizar los datos" no es un objetivo; "decidir cuántas unidades pedir para Sant Jordi" sí. Escribe la pregunta antes de abrir el editor.
- Instalar las librerías fuera del entorno virtual. Los
pip installde este módulo van dentro delvenvdel proyecto (M1). Siimport pandasfalla conModuleNotFoundError, casi seguro que el entorno no está activado. - Confundir media y mediana. Con datos asimétricos (y las ventas casi siempre lo son) cuentan historias distintas. Reporta ambas, o al menos sé consciente de cuál usas y por qué.
- Fiarse de datos que no has mirado. Antes de calcular nada, abre el CSV y lee 20 filas. Fechas imposibles, importes negativos o títulos mal escritos se detectan antes con los ojos que con código.
- Ejecutar celdas de notebook en desorden. El estado vive en memoria: si ejecutas la celda 5 antes que la 3, los resultados pueden ser incoherentes. Ante la duda: Kernel → Restart & Run All.
Ejercicios
- Clasifica estas tareas de Papyrus según el rol (analista, científico o ingeniero de datos) que mejor encaja: (a) un script nocturno que vuelca las ventas de la web de Django al CSV consolidado; (b) un informe mensual de unidades vendidas por título; (c) estimar cuántos ejemplares de El Quijote se venderán el próximo Sant Jordi.
- Con
csv.DictReaderystatistics, calcula el importe medio de las ventas deventas_2026.csvsolo del canalweby compáralo con el del canaltienda. ¿Qué hipótesis se te ocurre para explicar la diferencia? - Sin escribir código: para la pregunta "¿qué títulos se consultan en la web pero no se compran?", ¿qué datos necesitas además de
ventas_2026.csv? ¿En qué paso del flujo de trabajo estás al darte cuenta de que te falta información?
Soluciones
- (a) Ingeniero de datos: mueve y consolida datos, no responde preguntas. (b) Analista: describe qué pasó. (c) Científico de datos: predice y apoya una decisión. En Papyrus las tres tareas las hace la misma persona; los roles describen el tipo de trabajo, no un carné.
-
Hipótesis razonables (¡a verificar en 11-03, no a dar por ciertas!): en tienda se compran más unidades por operación (Marta recomienda en persona), o en la web pesan más los títulos baratos. Formular hipótesis comprobables es exactamente el paso 4 del flujo.import csv, statistics from pathlib import Path web, tienda = [], [] with open(Path("datos") / "ventas_2026.csv", encoding="utf-8", newline="") as f: for fila in csv.DictReader(f): destino = web if fila["canal"] == "web" else tienda destino.append(float(fila["importe"])) print(f"web: {statistics.mean(web):.2f} € en {len(web)} ventas") print(f"tienda: {statistics.mean(tienda):.2f} € en {len(tienda)} ventas") - Necesitas las visitas a las fichas de libro — están en los logs de la web de M10 (cada request a
/libro/<titulo>deja rastro), no en el CSV de ventas. Te das cuenta en el paso 2 (datos): la pregunta compara dos magnitudes (consultas y compras) y solo tienes una. Volver de la exploración a la búsqueda de datos es el bucle del diagrama funcionando.
Conclusión
Ya tienes el mapa: la ciencia de datos es responder preguntas con datos siguiendo el ciclo pregunta → datos → limpieza → exploración → conclusión; el ecosistema PyData reparte el trabajo entre NumPy (números), pandas (tablas), Matplotlib (gráficos) y scikit-learn (modelos); Jupyter es la mesa de trabajo habitual aunque todo funcione en scripts; y ventas_2026.csv — 487 ventas de enero a junio, con Sant Jordi latiendo el 23 de abril — es el material sobre el que responderemos las preguntas de Ana. También viste el límite: statistics y Counter llegan hasta donde llegan, y cada pregunta nueva cuesta otro bucle con conversiones a mano. La raíz del problema es que las listas de Python no saben de matemáticas: sumar dos listas las concatena, no suma sus números. La próxima lección presenta la estructura que sí sabe: el array de NumPy, donde importes * 1.04 hace en una línea — y mil veces más rápido — lo que hasta ahora exigía un bucle.
Curso de Programación en Python
Módulo 1: Introducción a Python
- Introducción a Python
- Configuración del Entorno de Desarrollo
- Sintaxis de Python y Tipos de Datos Básicos
- Variables y Constantes
- Entrada y Salida Básica
- Entornos Virtuales y Gestión de Paquetes
Módulo 2: Estructuras de Control
- Sentencias Condicionales
- Bucles: for y while
- Herramientas de Control de Flujo
- Comprensiones de Listas
Módulo 3: Funciones y Módulos
- Definición de Funciones
- Argumentos de Función
- Funciones Lambda
- Módulos y Paquetes
- Visión General de la Biblioteca Estándar
Módulo 4: Estructuras de Datos
Módulo 5: Programación Orientada a Objetos
Módulo 6: Manejo de Archivos
- Lectura y Escritura de Archivos
- Trabajo con Archivos CSV
- Manejo de Datos JSON
- Operaciones con Archivos y Directorios
Módulo 7: Manejo de Errores y Excepciones
- Introducción a las Excepciones
- Manejo de Excepciones
- Lanzamiento de Excepciones
- Excepciones Personalizadas
- Buenas Prácticas y Registro de Errores con logging
Módulo 8: Temas Avanzados
- Anotaciones de Tipos (type hints)
- Decoradores
- Generadores
- Administradores de Contexto
- Concurrencia: Hilos y Procesos
- Asyncio para Programación Asíncrona
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias con unittest
- Pruebas con pytest
- Desarrollo Guiado por Pruebas
- Técnicas de Depuración
- Uso de pdb para Depuración
Módulo 10: Desarrollo Web con Python
- Introducción al Desarrollo Web
- Fundamentos del Framework Flask
- Construcción de APIs REST con Flask
- Introducción a Django
- Construcción de Aplicaciones Web con Django
Módulo 11: Ciencia de Datos con Python
- Introducción a la Ciencia de Datos
- NumPy para Computación Numérica
- Pandas para Manipulación de Datos
- Matplotlib para Visualización de Datos
- Introducción al Aprendizaje Automático con scikit-learn
