Instalación y NumPy
1.1 · Instalar el trío del Data Science
Crea un entorno virtual para este bloque y usa pip:
$ python -m venv .venv
$ source .venv/bin/activate # Windows: .venv\Scripts\activate
$ pip install numpy pandas matplotlib
$ python
>>> import pandas as pd # si no lanza error, todo bien
1.2 · NumPy: arrays rápidos
NumPy es la base numérica. Su objeto estrella es el ndarray, una lista optimizada capaz de
hacer operaciones vectorizadas en todo el array:
import numpy as np
datos = np.array([1, 2, 3, 4])
print(datos * 2) # [2 4 6 8] (¡en un paso!)
print(datos.mean(), datos.sum()) # 2.5 10
columna = np.array([1, 2]) # vector fila
matrix = np.random.rand(2, 3) # matriz 2x3 aleatoria
for en Python puro es lentísimo; una operación vectorizada
de NumPy es 100× más rápida porque corre en C.pandas: Series y DataFrame
pandas es la herramienta estrella del análisis de datos. Trae dos estructuras:
Series (una columna, con índice) y DataFrame (una tabla, como una hoja de cálculo).
2.1 · Crear un DataFrame
import pandas as pd
datos = {
"producto": ["ratón", "teclado", "pad"],
"precio": [12, 45, 8],
"stock": [20, 5, 50],
}
df = pd.DataFrame(datos)
print(df)
print(df.shape) # (3 filas, 3 columnas)
print(df.columns) # nombres de columnas
2.2 · Acceder a series y celdas
precio_raton = df.loc[0, "precio"] # fila 0, col 'precio' → 12
precios = df["precio"] # toda la columna (una Series)
print(precios.mean()) # media de precios
df["columna"] selecciona columna (Series);
df.loc[fila, "columna"] selecciona celda; df.iloc[fila, col] selecciona por posición
numérica.Leer, filtrar y agrupar datos
3.1 · Leer un CSV de un solo golpe
import pandas as pd
df = pd.read_csv("ventas.csv")
print(df.head()) # primeras 5 filas
print(df.info()) # tipos de cada columna
print(df.describe()) # estadísticas de columnas numéricas
3.2 · Filtrar con condiciones booleanas
# ventas de la categoría 'periférico' con importe > 30
caras = df[(df["categoria"] == "periférico") & (df["importe"] > 30)]
print(caras)
& (y) y | (o), no and/or.
Y envuelve cada condición entre paréntesis: df[(a) & (b)].3.3 · Agrupar y agregar
groupby agrupa por columna y luego aplicamos una agregación:
por_categoria = df.groupby("categoria")["importe"].sum()
print(por_categoria) # total por categoría
resumen = df.groupby("mes").agg({"importe": ["sum", "mean"]})
print(resumen) # total y media por mes
Limpieza de datos
Los datos reales vienen con NaN (valores ausentes), cadenas con espacios y formatos mezclados. Limpiar es el 80 % del trabajo real del Data Science:
import pandas as pd
import numpy as np
df = pd.DataFrame({
"nombre": [" ana ", "Luis", None],
"edad": [25, np.nan, 30],
})
df["nombre"] = df["nombre"].str.strip() # quitar espacios
df["edad"] = df["edad"].fillna(df["edad"].mean()) # rellenar NaN con la media
df = df.dropna(subset=["nombre"]) # borrar filas sin nombre
df = df.drop_duplicates() # quitar duplicados
isna()/notna() detectan ausentes,
fillna(x) los rellena, dropna() los elimina y astype(int/float/str)
fuerza el tipo de una columna.Visualización con Matplotlib
Matplotlib pinta los gráficos. pyplot da la API sencilla: creas figura, llamas
al tipo de gráfico y muestras/guardas.
import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv("ventas.csv")
totales = df.groupby("mes")["importe"].sum()
plt.bar(totales.index, totales.values, color="#7c5cff")
plt.title("Ventas por mes")
plt.xlabel("Mes")
plt.ylabel("Importe")
plt.show() # o plt.savefig("grafico.png")
5.1 · Tipos de gráfico que dominan
%matplotlib inline
(Jupyter) o rellenando un bloque de celdas de salida (VS Code). En un script normal usa
plt.show().read_csv →
limpieza → filtro → groupby → gráfico. Esto es exactamente lo que se pide en la mayoría de
puestos de «analista de datos» junior.✍️ Los 15 ejercicios del bloque
Crea la carpeta python-b6/ y un archivo .py por ejercicio. Acuérdate de activar el
entorno virtual antes de ejecutarlos (source .venv/bin/activate).
Sección A · NumPy
1 Arrays vectorizados
Crea np.array([1, 2, 3, 4]) y muestra su doble, su suma, su raíz cuadrada (con
np.sqrt) y la media.
Ver solución
import numpy as np
datos = np.array([1, 2, 3, 4])
print(datos * 2)
print(datos.sum())
print(np.sqrt(datos))
print(datos.mean())
2 Matriz 3×3 aleatoria
Con np.random.randint crea una matriz 3×3 de números del 1 al 10 y muestra su forma, su
máximo y el máximo de cada columna (axis=0).
Ver solución
import numpy as np
m = np.random.randint(1, 11, size=(3, 3))
print(m)
print(m.shape)
print(m.max())
print(m.max(axis=0))
Sección B · pandas básico
3 Primer DataFrame
Crea un DataFrame a partir del dict
{"ciudad": ["Madrid", "Valencia", "Bilbao"], "votos": [100, 80, 60]} y muestra las 2 primeras
filas con head(2), el shape y las columnas.
Ver solución
import pandas as pd
df = pd.DataFrame({"ciudad": ["Madrid", "Valencia", "Bilbao"],
"votos": [100, 80, 60]})
print(df.head(2))
print(df.shape)
print(df.columns)
4 Acceder a celdas
Sobre el DataFrame anterior, muetra con loc la fila 1 y la celda
[2, "votos"], y con iloc la primera fila por posición.
Ver solución
import pandas as pd
df = pd.DataFrame({"ciudad": ["Madrid", "Valencia", "Bilbao"],
"votos": [100, 80, 60]})
print(df.loc[1])
print(df.loc[2, "votos"])
print(df.iloc[0])
5 Describe tu tabla
Crear un DataFrame con {"alumno": [...5 nombres...], "nota": [...5 notas...]} y
muestra describe() de la columna nota y su desviación típica con .std().
Ver solución
import pandas as pd
df = pd.DataFrame({"alumno": ["a", "b", "c", "d", "e"],
"nota": [7, 8, 9, 6, 10]})
print(df["nota"].describe())
print(df["nota"].std())
Sección C · Filtrar, agrupar y limpiar
6 Filtro de mayores
Sobre un DataFrame de {"nombre": [...], "edad": [...]}, muestra solo las filas con edad
mayor de 25 usando la condición booleana entre paréntesis.
Ver solución
import pandas as pd
df = pd.DataFrame({"nombre": ["Ana", "Luis", "Rita", "Paz"],
"edad": [24, 30, 28, 19]})
mayores = df[df["edad"] > 25]
print(mayores)
7 Filtro con & y |
Del DataFrame anterior, muestra los mayores de 25 o los que empiezan por R (usa el módulo str
de pandas: df["nombre"].str.startswith("R")) combinados con |.
Ver solución
import pandas as pd
df = pd.DataFrame({"nombre": ["Ana", "Luis", "Rita", "Paz"],
"edad": [24, 30, 28, 19]})
sel = df[(df["edad"] > 25) | df["nombre"].str.startswith("R")]
print(sel)
8 Groupby de ventas
Crea un DataFrame de ventas
{"tienda": ["A", "A", "B", "B"], "importe": [100, 50, 200, 75]} y con groupby
muestra la suma y la media por tienda.
Ver solución
import pandas as pd
df = pd.DataFrame({"tienda": ["A", "A", "B", "B"],
"importe": [100, 50, 200, 75]})
print(df.groupby("tienda")["importe"].sum())
print(df.groupby("tienda")["importe"].mean())
9 Leer CSV con pandas
Crea alumnos.csv (con las librerías csv) con nombre,nota para 4 alumnos, luego
léelo con pd.read_csv y muestra head() y la nota media.
Ver solución
import csv
import pandas as pd
with open("alumnos.csv", "w", newline="", encoding="utf-8") as f:
w = csv.writer(f)
w.writerow(["nombre", "nota"])
w.writerows([["Ana", 8], ["Luis", 7], ["Rita", 9], ["Paz", 5]])
df = pd.read_csv("alumnos.csv")
print(df.head())
print(df["nota"].mean())
10 Rellenar NaN
Crea un DataFrame con {"edad": [25, None, 30, None]} y rellena los ausentes con la media de
la columna usando fillna. Muestra el resultado.
Ver solución
import pandas as pd
df = pd.DataFrame({"edad": [25, None, 30, None]})
df["edad"] = df["edad"].fillna(df["edad"].mean())
print(df)
11 Quitar duplicados y espacios
Crea un DataFrame con nombres con espacios y una fila duplicada. Limpia con str.strip() y
drop_duplicates(). Muestra el resultado.
Ver solución
import pandas as pd
df = pd.DataFrame({"nombre": [" Ana ", "Luis", "Ana", "Luis"]})
df["nombre"] = df["nombre"].str.strip()
df = df.drop_duplicates()
print(df)
12 Gráfico de barras
Con un DataFrame de ventas por mes, pinta un plt.bar() con título y etiquetas, y guárdalo con
plt.savefig("barras.png").
Ver solución
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({"mes": ["ene", "feb", "mar"],
"importe": [100, 150, 90]})
plt.bar(df["mes"], df["importe"], color="#7c5cff")
plt.title("Ventas por mes")
plt.xlabel("Mes")
plt.ylabel("Importe")
plt.savefig("barras.png")
13 Línea de tendencia
Pinta con plt.plot la serie [5, 8, 6, 10, 12] (días 1 a 5) con un marcador de
puntos y título «Tendencia».
Ver solución
import matplotlib.pyplot as plt
dias = [1, 2, 3, 4, 5]
valores = [5, 8, 6, 10, 12]
plt.plot(dias, valores, marker="o")
plt.title("Tendencia")
plt.show()
14 Histograma estándar
Con plt.hist muestra la distribución de las notas de una lista de 20 notas aleatorias entre
0 y 10 (random.randint), con 10 contenedores (bins=10).
Ver solución
import random
import matplotlib.pyplot as plt
notas = [random.randint(0, 10) for _ in range(20)]
plt.hist(notas, bins=10)
plt.title("Distribución de notas")
plt.show()
15 🏆 Proyecto integrador: «análisis de ventas»
Crea analisis_ventas.py: un mini informe de un CSV de ventas usando pandas y un gráfico.
Requisitos:
- Genera
ventas.csv(12 filas) con columnasmes, categoria, importe(categorías: periférico y pantalla; importes aleatorios). - Léelo con
pd.read_csv. - Añade 2 filas con importe/valor ausente (
NaN) y límpialas condropnaofillna. - Filtra solo las ventas con importe mayor a un umbral (p. ej. 60).
- Agrupa con
groupby("categoria")["importe"].sum(). - Pinta un
plt.bardel total por categoría y guardaresumen_ventas.png. - Muestra por consola el total general y la media por categoría.
- Define una función con docstring para una parte del análisis.
Ver una solución posible
import csv
import random
import pandas as pd
import matplotlib.pyplot as plt
def generar_csv(ruta):
"""Crea el fichero de ventas con 12 filas y 2 huecos a propósito."""
filas = []
for mes in ["ene", "feb", "mar"]:
filas.append({"mes": mes, "categoria": "periférico", "importe": random.randint(30, 90)})
filas.append({"mes": mes, "categoria": "pantalla", "importe": random.randint(80, 200)})
filas.append({"mes": "abr", "categoria": "periférico", "importe": None})
filas.append({"mes": "abr", "categoria": "pantalla", "importe": None})
with open(ruta, "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=["mes", "categoria", "importe"])
w.writeheader()
w.writerows(filas)
generar_csv("ventas.csv")
df = pd.read_csv("ventas.csv")
df = df.dropna(subset=["importe"])
caras = df[df["importe"] > 60]
totales = df.groupby("categoria")["importe"].sum()
medias = df.groupby("categoria")["importe"].mean()
print(f"Ventas altas: {len(caras)}")
print(totales)
print(medias)
plt.bar(totales.index, totales.values, color="#7c5cff")
plt.title("Ventas totales por categoría")
plt.savefig("resumen_ventas.png")
📝 Examen del Bloque 6
Dos partes: un test teórico autoevaluable (mínimo 70 %) y un reto práctico de autocorrección con laboratorio.
Parte B · Reto «tiny dataset»
Crea dataset.py donde practiques el ciclo pandas. Valida tú mismo/a estos criterios.
Mínimo para aprobar: 6 de 8 casillas.
Cumplidos: 0 / 8