Hoja de referencia de pandas (Python)

40 elementos esenciales con sintaxis y ejemplos. Busca o filtra por grupo.

read_csv

Carga un archivo CSV en un DataFrame. Los demás ejemplos asumen: import pandas as pd; df = pd.read_csv("sales_flat.csv").

pd.read_csv(path, sep=',', usecols=None, dtype=None)
import pandas as pd

df = pd.read_csv("sales_flat.csv")
print(df.shape)

read_csv(parse_dates=)

Convierte columnas de fecha a datetime al leer, para que .dt y resample funcionen de inmediato.

pd.read_csv(path, parse_dates=["col"])
orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
print(orders["order_date"].dtype)

read_sql

Ejecuta una consulta SQL y devuelve el resultado como DataFrame.

pd.read_sql(query, connection)
import sqlite3

con = sqlite3.connect("sunshine_grocers.db")
stores = pd.read_sql("SELECT * FROM stores WHERE region = 'South'", con)
con.close()

to_csv

Guarda un DataFrame en CSV. index=False evita escribir el índice de filas como columna extra.

df.to_csv(path, index=False)
df[df["region"] == "South"].to_csv("south_sales.csv", index=False)

to_excel

Escribe en un archivo .xlsx (requiere openpyxl). Usa pd.ExcelWriter para escribir varias hojas en un mismo archivo.

df.to_excel(path, sheet_name='Sheet1', index=False)
by_region = df.groupby("region", as_index=False)["net_sales"].sum()
by_cat = df.groupby("category", as_index=False)["net_sales"].sum()

with pd.ExcelWriter("summary.xlsx") as writer:
    by_region.to_excel(writer, sheet_name="Region", index=False)
    by_cat.to_excel(writer, sheet_name="Category", index=False)

head / tail / shape

Primeras o últimas n filas (5 por defecto) y el tamaño (filas, columnas).

df.head(n) | df.tail(n) | df.shape
print(df.head(3))
print(df.shape)

info / dtypes

Nombres de columnas, tipos de datos y cantidad de valores no nulos. La primera revisión después de cargar datos.

df.info() | df.dtypes
df.info()
print(df.dtypes)

describe

Estadísticas resumidas (conteo, media, desviación, mínimo, cuartiles, máximo) de las columnas numéricas.

df.describe(include=None)
print(df[["quantity", "unit_price", "net_sales"]].describe().round(2))

value_counts

Cuenta cada valor distinto de una columna; normalize=True devuelve proporciones.

s.value_counts(normalize=False)
print(df["channel"].value_counts())
print(df["segment"].value_counts(normalize=True).round(3))

Select columns

Una columna devuelve una Serie; una lista de columnas devuelve un DataFrame.

df["col"] | df[["col1", "col2"]]
sales = df["net_sales"]
subset = df[["order_date", "store_name", "net_sales"]]

loc

Selecciona por etiquetas y condiciones booleanas. También es la forma segura de asignar valores a un subconjunto filtrado.

df.loc[row_condition, columns]
south = df.loc[df["region"] == "South", ["store_name", "net_sales"]]

df.loc[df["discount"] > 0, "promo"] = "Yes"

iloc

Selecciona por posición entera (empieza en 0 y excluye el final).

df.iloc[rows, cols]
first_rows = df.iloc[:5, :4]
last_row = df.iloc[-1]

Boolean filter

Filtra filas con condiciones. Pon cada condición entre paréntesis y usa &, |, ~ (no and/or).

df[(cond1) & (cond2)] | | for OR | ~ for NOT
big_online = df[(df["channel"] == "Online") & (df["net_sales"] > 30)]
print(len(big_online))

isin

Conserva las filas cuyo valor está en una lista (como IN en SQL).

df[df["col"].isin([v1, v2])]
fresh = df[df["category"].isin(["Produce", "Dairy", "Bakery"])]

query

Filtra con una expresión de texto fácil de leer. Usa @var para referirte a variables de Python.

df.query("expression")
min_sales = 25
result = df.query("region == 'West' and net_sales > @min_sales")

between

TRUE cuando el valor está dentro de un rango (inclusivo por defecto). También sirve con fechas en texto ISO.

s.between(left, right, inclusive='both')
jan_2025 = df[df["order_date"].between("2025-01-01", "2025-01-31")]

New column / assign

Crea columnas calculadas con operaciones vectorizadas. assign devuelve un DataFrame nuevo, útil para encadenar.

df["new"] = expr | df.assign(new=expr)
df["profit"] = df["net_sales"] - df["cost"]
df = df.assign(margin_pct=lambda d: d["profit"] / d["net_sales"] * 100)

rename

Renombra columnas (o etiquetas del índice) y devuelve un DataFrame nuevo.

df.rename(columns={"old": "new"})
out = df.rename(columns={"net_sales": "Net Sales", "store_name": "Store"})

sort_values

Ordena las filas por una o varias columnas.

df.sort_values(by, ascending=True)
top = df.sort_values(["net_sales", "order_date"], ascending=[False, True]).head(10)

drop / drop_duplicates

Elimina columnas, o elimina filas repetidas (todas las columnas o un subconjunto).

df.drop(columns=[...]) | df.drop_duplicates(subset=None, keep='first')
dirty = pd.read_csv("sales_dirty.csv")
clean = dirty.drop_duplicates()
print(len(dirty) - len(clean), "duplicates removed")
slim = clean.drop(columns=["brand", "cost"])

str methods

Limpieza de texto vectorizada sobre una columna.

s.str.strip() | .str.title() | .str.upper() | .str.replace() | .str.contains()
dirty = pd.read_csv("sales_dirty.csv")
dirty["store_name"] = dirty["store_name"].str.strip().str.title()
dirty["category"] = dirty["category"].str.title()

to_numeric / astype

Convierte texto en números; errors='coerce' convierte los valores inválidos en NaN. astype cambia el tipo de una columna.

pd.to_numeric(s, errors='coerce') | s.astype(type)
dirty = pd.read_csv("sales_dirty.csv")
dirty["net_sales"] = pd.to_numeric(dirty["net_sales"].str.replace("$", "", regex=False))
dirty["quantity"] = dirty["quantity"].str.extract(r"(\d+)", expand=False).astype(int)

apply

Aplica una función a cada valor (Serie) o a cada fila (axis=1). Flexible, pero más lenta que el código vectorizado.

s.apply(func) | df.apply(func, axis=1)
def size_band(x):
    return "Large" if x >= 30 else "Small"

df["basket"] = df["net_sales"].apply(size_band)
print(df["basket"].value_counts())

where (numpy)

IF vectorizado y rápido para crear una columna a partir de una condición.

np.where(condition, value_if_true, value_if_false)
import numpy as np

df["is_promo"] = np.where(df["discount"] > 0, "Promo", "Regular")

isna / notna

Detecta valores faltantes; .sum() da el conteo por columna.

df.isna().sum() | s.notna()
dirty = pd.read_csv("sales_dirty.csv")
print(dirty.isna().sum())

fillna

Reemplaza valores faltantes. Asigna el resultado de nuevo (inplace en una sola columna no funciona con copy-on-write en pandas 3).

s.fillna(value) | df.fillna({"col": value})
dirty = pd.read_csv("sales_dirty.csv")
dirty["region"] = dirty["region"].fillna("Unknown")

dropna

Elimina filas con valores faltantes (opcionalmente solo en algunas columnas).

df.dropna(subset=None, how='any')
dirty = pd.read_csv("sales_dirty.csv")
with_region = dirty.dropna(subset=["region"])

groupby + sum

Divide las filas en grupos y agrega cada uno. as_index=False devuelve un DataFrame normal.

df.groupby(keys)[col].sum()
by_region = (df.groupby("region", as_index=False)["net_sales"].sum()
               .sort_values("net_sales", ascending=False))
print(by_region)

groupby + agg (named)

Varias agregaciones a la vez con nombres de salida claros.

df.groupby(key).agg(new=("col", "func"), ...)
summary = df.groupby("store_name").agg(
    sales=("net_sales", "sum"),
    orders=("order_id", "nunique"),
    avg_line=("net_sales", "mean"),
).round(2)
print(summary.head())

groupby + transform

Devuelve el resultado del grupo alineado con cada fila original, por ejemplo la participación de cada línea en su región.

df.groupby(key)[col].transform(func)
df["region_total"] = df.groupby("region")["net_sales"].transform("sum")
df["pct_of_region"] = df["net_sales"] / df["region_total"] * 100

nlargest / nsmallest

Los n valores más altos o más bajos sin ordenar todo el conjunto de datos.

s.nlargest(n) | df.nlargest(n, col)
top5 = df.groupby("product_name")["net_sales"].sum().nlargest(5)
print(top5)

merge

Une dos DataFrames por columnas clave (como JOIN en SQL). Usa validate= para detectar duplicados inesperados.

pd.merge(left, right, on=key, how='inner'|'left'|'right'|'outer')
orders = pd.read_csv("orders.csv")
stores = pd.read_csv("stores.csv")
m = orders.merge(stores[["store_id", "store_name", "region"]],
                 on="store_id", how="left", validate="many_to_one")

concat

Apila DataFrames verticalmente (o lado a lado con axis=1).

pd.concat([df1, df2], ignore_index=True)
y2024 = df[df["order_date"] < "2025-01-01"]
y2025 = df[df["order_date"] >= "2025-01-01"]
all_years = pd.concat([y2024, y2025], ignore_index=True)

pivot_table

Crea una tabla dinámica estilo Excel.

df.pivot_table(index, columns, values, aggfunc='sum', fill_value=0, margins=False)
pt = df.pivot_table(index="region", columns="category",
                    values="net_sales", aggfunc="sum",
                    fill_value=0, margins=True).round(0)
print(pt)

melt

Convierte columnas anchas en filas largas (lo opuesto a pivot).

df.melt(id_vars, value_vars, var_name, value_name)
budget = pd.read_csv("budget.csv")
long = budget.melt(id_vars=["month", "store_id"],
                   value_vars=["revenue_budget", "expense_budget"],
                   var_name="type", value_name="amount")

crosstab

Tabla de frecuencias de dos columnas. normalize='index' da porcentajes por fila.

pd.crosstab(index, columns, normalize=False)
print(pd.crosstab(df["segment"], df["channel"], normalize="index").round(3))

to_datetime

Convierte texto en fecha y hora. format='mixed' maneja columnas con varios formatos de fecha.

pd.to_datetime(s, format=None, errors='raise')
df["order_date"] = pd.to_datetime(df["order_date"])

dirty = pd.read_csv("sales_dirty.csv")
dirty["order_date"] = pd.to_datetime(dirty["order_date"], format="mixed")

.dt accessor

Extrae partes de valores de fecha y hora.

s.dt.year | .dt.month | .dt.day_name() | .dt.to_period('M')
df["order_date"] = pd.to_datetime(df["order_date"])
df["year"] = df["order_date"].dt.year
df["weekday"] = df["order_date"].dt.day_name()
df["month"] = df["order_date"].dt.to_period("M")

resample

Agrupa una serie de tiempo por período: 'D' día, 'W' semana, 'MS' inicio de mes, 'QS' inicio de trimestre, 'YS' inicio de año.

df.resample(rule, on=date_col).agg(...)
df["order_date"] = pd.to_datetime(df["order_date"])
monthly = df.resample("MS", on="order_date")["net_sales"].sum()
print(monthly.head())

rolling / pct_change

Ventanas móviles (por ejemplo promedio de 3 meses) y crecimiento contra el período anterior.

s.rolling(window).mean() | s.pct_change()
df["order_date"] = pd.to_datetime(df["order_date"])
monthly = df.resample("MS", on="order_date")["net_sales"].sum()
trend = pd.DataFrame({
    "sales": monthly,
    "ma_3m": monthly.rolling(3).mean(),
    "mom_pct": monthly.pct_change() * 100,
}).round(1)