Hoja de referencia · 12 tareas · 49 fragmentos, todos probados en pandas 2.3

Hoja de referencia de pandas para analistas de datos

El pandas que usas en el trabajo, agrupado por tarea. Cada fragmento se ejecuta tal como está escrito sobre las tablas de Harbor & Pine, y cada grupo enlaza con los niveles que lo enseñan.

pandas 2.3. Cada tabla ya es un DataFrame con el mismo nombre que la tabla SQL (customers, orders, order_items …); las columnas de fecha se leen como datetime64; pd y np ya están importados. La última línea de cada fragmento es el resultado.

Primer vistazo a una tabla

Primeras y últimas filas

orders.head(10)
orders.tail(3)

Tamaño, columnas y tipos

orders.shape          # (rows, columns)
orders.dtypes
orders.info()

Estadísticas resumen

products.describe()                 # numeric columns
products.describe(include="object")  # text columns

Contar cada valor

orders["status"].value_counts()
orders["status"].value_counts(normalize=True).round(3)  # shares

Cuántos valores distintos hay

orders["customer_id"].nunique()

Seleccionar columnas y filas

Una columna es una Series, una lista da un DataFrame

products["unit_price"]                       # Series
products[["name", "category", "unit_price"]]  # DataFrame

Filas y columnas por etiqueta

products.loc[products["category"] == "Lighting", ["name", "unit_price"]]

Filas y columnas por posición

products.iloc[:5, :3]

Filtrar filas

Una condición

orders[orders["channel"] == "marketplace"]

Varias condiciones

products[(products["category"] == "Decor") & (products["unit_price"] < 50)]

Usa & | ~ (no and/or/not) y pon cada condición entre paréntesis.

En una lista, en un rango

products[products["category"].isin(["Decor", "Kitchen"])]
products[products["unit_price"].between(50, 100)]  # inclusive both ends

El texto contiene

customers[customers["email"].str.contains("@gmail.com", regex=False, na=False)]

El mismo filtro como cadena de consulta

orders.query("channel == 'app' and shipping_fee > 10")

Ordenar y top N

Ordenar por varias columnas

products.sort_values(["category", "unit_price"], ascending=[True, False])

Top 10 según una columna

products.nlargest(10, "unit_price")[["name", "unit_price"]]

Índice limpio de 0..n tras ordenar

products.sort_values("unit_price", ascending=False).reset_index(drop=True)

Columnas nuevas

Aritmética con columnas completas

items = order_items.copy()
items["revenue"] = items["quantity"] * items["unit_price"] * (1 - items["discount_pct"] / 100)
items.head()

If/else sobre una columna

products["tier"] = np.where(products["unit_price"] >= 200, "premium", "standard")
products["tier"].value_counts()

Tramos con pd.cut

products["band"] = pd.cut(products["unit_price"], bins=[0, 50, 200, np.inf],
                          labels=["under 50", "50-199", "200+"], right=False)
products["band"].value_counts()

right=False hace que cada tramo incluya su extremo izquierdo: 50 cae en "50-199".

Agrupar y contar

Filas por grupo

orders.groupby("channel").size()

Un número por grupo

orders.groupby("channel")["shipping_fee"].mean().round(2)

Varios números por grupo (agregación con nombre)

products.groupby("category", as_index=False).agg(
    products=("product_id", "count"),
    avg_price=("unit_price", "mean"),
    max_price=("unit_price", "max"),
)

Dos claves, desplegadas en una tabla

orders.groupby(["channel", "status"]).size().unstack(fill_value=0)

Conservar solo los grupos grandes (como HAVING)

per_customer = orders.groupby("customer_id").size()
per_customer[per_customer >= 20]

Tabla dinámica

orders.pivot_table(index="channel", columns="status",
                   values="order_id", aggfunc="count", fill_value=0)

Unir dos tablas (merge)

Merge interno, con comprobación

lines = order_items.merge(products[["product_id", "name", "category"]],
                         on="product_id", how="inner", validate="many_to_one")
len(lines) == len(order_items)

validate= lanza un error si la clave no es única donde esperas que lo sea.

Filas sin coincidencia (anti-join)

m = customers.merge(orders[["customer_id"]].drop_duplicates(),
                    on="customer_id", how="left", indicator=True)
m[m["_merge"] == "left_only"]

Lo mismo con isin

customers[~customers["customer_id"].isin(orders["customer_id"])]

Nombres de clave distintos y luego agrupar

lines = order_items.merge(products, on="product_id", suffixes=("_paid", "_list"))
lines["revenue"] = lines["quantity"] * lines["unit_price_paid"] * (1 - lines["discount_pct"] / 100)
lines.groupby("category")["revenue"].sum().sort_values(ascending=False).round(2)

Las dos tablas tienen unit_price: suffixes conserva ambas e indica cuál es cuál.

Manejar valores faltantes (NaN)

Valores faltantes por columna

customers.isna().sum()

Filas donde falta un valor

products[products["unit_cost"].isna()]

Rellenar o eliminar

customers["referral_source"].fillna("unknown").value_counts()
products.dropna(subset=["unit_cost"])

mean() omite los NaN

products["unit_cost"].mean()            # average of the known costs
products["unit_cost"].fillna(0).mean()  # treats missing as 0: lower

Count incluye u omite los NaN

customers["referral_source"].count()        # non-missing only
len(customers)                               # every row
customers["referral_source"].value_counts(dropna=False)

Limpiar texto y encontrar duplicados

Quitar espacios y corregir mayúsculas

customers["state_clean"] = customers["state"].str.strip().str.upper()
customers["state_clean"].value_counts().head()

Dividir texto

customers["email"].str.split("@").str[1].value_counts().head()

Encontrar duplicados con una clave limpia

key = customers["email"].str.strip().str.lower()
customers[key.duplicated(keep=False)].sort_values("email")

Eliminar duplicados y conservar el primero

customers.assign(key=customers["email"].str.strip().str.lower()) \
         .drop_duplicates(subset="key", keep="first")

Fechas

Convertir texto en fechas

pd.to_datetime(pd.Series(["2025-03-01", "not a date"]), errors="coerce")

Partes de una fecha

orders["order_date"].dt.year.value_counts().sort_index()
orders["order_date"].dt.day_name().value_counts()

Totales mensuales

orders.groupby(orders["order_date"].dt.to_period("M")).size().tail(12)

Filtrar un rango de fechas

orders[(orders["order_date"] >= "2024-03-01") & (orders["order_date"] < "2024-04-01")]

Días entre dos fechas

r = (returns.merge(order_items[["order_item_id", "order_id"]], on="order_item_id")
           .merge(orders[["order_id", "order_date"]], on="order_id"))
(r["returned_on"] - r["order_date"].dt.normalize()).dt.days.describe()

Ranking, totales acumulados y cambios

Ranking dentro de cada grupo

products["price_rank"] = products.groupby("category")["unit_price"].rank(method="dense", ascending=False)
products[products["price_rank"] <= 3].sort_values(["category", "price_rank"])

Numerar cada fila dentro de su grupo

o = orders.sort_values("order_date")
o["order_n"] = o.groupby("customer_id").cumcount() + 1
o[["customer_id", "order_date", "order_n"]].head()

Total acumulado, cambio y media móvil

monthly = orders.groupby(orders["order_date"].dt.to_period("M")).size()
pd.DataFrame({
    "orders": monthly,
    "running": monthly.cumsum(),
    "mom_pct": (monthly.pct_change() * 100).round(1),
    "avg_3m": monthly.rolling(3).mean().round(1),
})

Métricas de negocio habituales

Valor promedio del pedido (AOV)

done = orders.loc[orders["status"] == "completed", ["order_id"]]
lines = order_items.merge(done, on="order_id")
revenue = (lines["quantity"] * lines["unit_price"] * (1 - lines["discount_pct"] / 100)).sum()
round(revenue / lines["order_id"].nunique(), 2)

Tasa de conversión por fuente

(web_sessions.groupby("source")["converted"].mean() * 100).round(2).sort_values(ascending=False)

Tasa de devolución por categoría

lines = order_items.merge(products[["product_id", "category"]], on="product_id")
lines["returned"] = lines["order_item_id"].isin(returns["order_item_id"])
(lines.groupby("category")["returned"].mean() * 100).round(1)

https://analystquest.com/es/resources/pandas-cheat-sheet/ · Niveles gratis para practicar cada fragmento: analystquest.com

Más recursos

Hoja de referencia

Hoja de referencia de SQL

Hoja de referencia de SQL agrupada por tarea: filtrar, agrupar y contar, JOIN, NULL, fechas, CTE y funciones de ventana. Cada consulta se ejecuta sobre una base de datos real de una tienda.

Hoja de referencia

Hoja de referencia de Excel

Fórmulas de Excel para analistas, agrupadas por tarea: SUMIFS, COUNTIFS, XLOOKUP, IF, limpieza de texto, fechas y duplicados, con los atajos que más tiempo ahorran.

Preparación para entrevistas

Preguntas de entrevista

Preguntas de entrevistas reales de analista, cada una con una respuesta modelo, la respuesta que resta puntos y un nivel para practicarla. Los términos que no tengas claros están en el glosario.

Elige qué puede ejecutarse en este sitio. Puedes cambiarlo cuando quieras desde "Configurar cookies", al pie de cada página.