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 · 12 tareas · 49 fragmentos, todos probados en pandas 2.3
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.
orders.head(10)
orders.tail(3) orders.shape # (rows, columns)
orders.dtypes
orders.info() products.describe() # numeric columns
products.describe(include="object") # text columns orders["status"].value_counts()
orders["status"].value_counts(normalize=True).round(3) # shares orders["customer_id"].nunique() products["unit_price"] # Series
products[["name", "category", "unit_price"]] # DataFrame products.loc[products["category"] == "Lighting", ["name", "unit_price"]] products.iloc[:5, :3] orders[orders["channel"] == "marketplace"] products[(products["category"] == "Decor") & (products["unit_price"] < 50)] Usa & | ~ (no and/or/not) y pon cada condición entre paréntesis.
products[products["category"].isin(["Decor", "Kitchen"])]
products[products["unit_price"].between(50, 100)] # inclusive both ends customers[customers["email"].str.contains("@gmail.com", regex=False, na=False)] orders.query("channel == 'app' and shipping_fee > 10") products.sort_values(["category", "unit_price"], ascending=[True, False]) products.nlargest(10, "unit_price")[["name", "unit_price"]] products.sort_values("unit_price", ascending=False).reset_index(drop=True) items = order_items.copy()
items["revenue"] = items["quantity"] * items["unit_price"] * (1 - items["discount_pct"] / 100)
items.head() products["tier"] = np.where(products["unit_price"] >= 200, "premium", "standard")
products["tier"].value_counts() 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".
orders.groupby("channel").size() orders.groupby("channel")["shipping_fee"].mean().round(2) products.groupby("category", as_index=False).agg(
products=("product_id", "count"),
avg_price=("unit_price", "mean"),
max_price=("unit_price", "max"),
) orders.groupby(["channel", "status"]).size().unstack(fill_value=0) per_customer = orders.groupby("customer_id").size()
per_customer[per_customer >= 20] orders.pivot_table(index="channel", columns="status",
values="order_id", aggfunc="count", fill_value=0) 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.
m = customers.merge(orders[["customer_id"]].drop_duplicates(),
on="customer_id", how="left", indicator=True)
m[m["_merge"] == "left_only"] customers[~customers["customer_id"].isin(orders["customer_id"])] 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.
customers.isna().sum() products[products["unit_cost"].isna()] customers["referral_source"].fillna("unknown").value_counts()
products.dropna(subset=["unit_cost"]) products["unit_cost"].mean() # average of the known costs
products["unit_cost"].fillna(0).mean() # treats missing as 0: lower customers["referral_source"].count() # non-missing only
len(customers) # every row
customers["referral_source"].value_counts(dropna=False) customers["state_clean"] = customers["state"].str.strip().str.upper()
customers["state_clean"].value_counts().head() customers["email"].str.split("@").str[1].value_counts().head() key = customers["email"].str.strip().str.lower()
customers[key.duplicated(keep=False)].sort_values("email") customers.assign(key=customers["email"].str.strip().str.lower()) \
.drop_duplicates(subset="key", keep="first") pd.to_datetime(pd.Series(["2025-03-01", "not a date"]), errors="coerce") orders["order_date"].dt.year.value_counts().sort_index()
orders["order_date"].dt.day_name().value_counts() orders.groupby(orders["order_date"].dt.to_period("M")).size().tail(12) orders[(orders["order_date"] >= "2024-03-01") & (orders["order_date"] < "2024-04-01")] 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() products["price_rank"] = products.groupby("category")["unit_price"].rank(method="dense", ascending=False)
products[products["price_rank"] <= 3].sort_values(["category", "price_rank"]) o = orders.sort_values("order_date")
o["order_n"] = o.groupby("customer_id").cumcount() + 1
o[["customer_id", "order_date", "order_n"]].head() 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),
}) 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) (web_sessions.groupby("source")["converted"].mean() * 100).round(2).sort_values(ascending=False) 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
Hoja de referencia
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
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 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.