---
title: "0.5.3 pandas: groupby, merge, resample y rolling"
description: "Selección con loc e iloc, filtros, groupby, merge, pivot, resample y ventanas rolling y expanding con los precios y las operaciones de SINT."
url: "https://pythonparatrading.com/curso-python-trading/nivel-0/pandas-groupby-merge-resample-y-rolling/"
lang: "es"
image: "https://pythonparatrading.com/og/curso-python-trading/nivel-0/pandas-groupby-merge-resample-y-rolling.png"
---

# 0.5.3 · Selección, filtrado, groupby, merge, pivot, resample y ventanas móviles

> Casi todo el research diario con pandas se reduce a ocho operaciones: seleccionar, filtrar, agrupar, combinar, pivotar, cambiar de frecuencia y calcular sobre ventanas. Esta lección las recorre con SINT hasta llegar a su volatilidad móvil y su drawdown, sin usar información del futuro.

- Curso: [Nivel 0: Python desde cero y mentalidad de datos](https://pythonparatrading.com/curso-python-trading/nivel-0/)
- Módulo: 0.5 · Computación numérica y datos
- Duración: 55 min
- Requisitos: [0.5.2 · pandas 3.0: Series, DataFrame, índices temporales, Copy-on-Write, tipo str y pd.col()](https://pythonparatrading.com/curso-python-trading/nivel-0/pandas-3-series-y-dataframe/)

## Al terminar esta lección

- Seleccionar filas y columnas por etiqueta con `loc` y por posición con `iloc`, y filtrar sesiones con condiciones combinadas.
- Calcular rentabilidades mensuales con `resample` y resumirlas por año y por día de la semana con `groupby` y `pivot`.
- Combinar el libro de operaciones con los precios mediante `merge` y comprobar la relación entre las tablas con `validate`.
- Calcular la volatilidad móvil con `rolling` y el drawdown con `expanding`/`cummax`, y explicar por qué no usan datos futuros.

## Seleccionar: loc e iloc

La lección 0.5.2 presentó las `Series` y los `DataFrame`. Para trabajar con ellos hay dos selectores, y confundirlos es
uno de los errores más comunes:

| Selector | Selecciona por | Ejemplo | Corte `a:b` |
|---|---|---|---|
| `loc` | Etiqueta: fechas, nombres de columna | `precios.loc["2023-01-02", "cierre"]` | Incluye `b` |
| `iloc` | Posición entera, desde 0 | `precios.iloc[-1, 3]` | Excluye `b`, como Python |

Los dos aceptan `[filas, columnas]`, y cada parte puede ser una etiqueta (o posición), una lista, un corte o una
máscara de `bool`:

```python
import numpy as np
import pandas as pd

precios = pd.read_csv("sint_diario.csv", parse_dates=["fecha"],
                      index_col="fecha")
cierre = precios["cierre"]
r = cierre.pct_change()

print(precios.loc["2023-01-02", "cierre"])
print(precios.iloc[-1, 3], precios.columns[3])
precios.iloc[-3:, [3, 4]]
```
```output
105.44
142.22 cierre
            cierre  volumen
fecha
2025-12-29  139.56   801992
2025-12-30  139.98  1510567
2025-12-31  142.22  2459297
```

La última fila tiene posición −1 y la columna `cierre` es la cuarta (posición 3). `iloc` es útil para «las últimas n
sesiones» o «la primera fila»; para todo lo demás, `loc` con fechas y nombres es más legible y no se rompe si cambia el
orden de las columnas.

## Filtrar sesiones

Una máscara de `bool` del mismo índice selecciona las filas en que vale `True`, como en NumPy (lección 0.5.1). Las
condiciones se combinan con `&` (y), `|` (o) y `~` (no), **cada una entre paréntesis**: `&` tiene más prioridad que
`<`, y `and`/`or` de Python no funcionan con máscaras.

```python
volumen_alto = precios["volumen"] > precios["volumen"].median()
caidas = precios[(r < -0.03) & volumen_alto]
print(len(caidas), "sesiones")
print(caidas.index.year.value_counts().sort_index().to_dict())

ops = pd.read_csv("operaciones_sint.csv",
                  parse_dates=["fecha_entrada", "fecha_salida"])
otras = ops[~ops["simbolo"].isin(["SINT"])]
print(otras["simbolo"].value_counts().to_dict())
```
```output
10 sesiones
{2021: 1, 2022: 8, 2025: 1}
{'RVAR': 4, 'ORO': 3, 'TECH': 3}
```

De las diez sesiones con caída de más del 3 % y volumen por encima de la mediana, la mayoría están en 2022, el año de la
caída de SINT. `isin` comprueba la pertenencia a una lista y `~` la niega: diez operaciones del libro son de otros
activos de la cartera ficticia.

## Cambiar de frecuencia: resample

`resample` agrupa un índice de fechas en periodos (semanas, meses, años) y aplica una agregación a cada uno. Para
rentabilidades mensuales se toma el **último** cierre de cada mes y se calcula su variación:

```python
cierre_mes = cierre.resample("ME").last()
r_mes = cierre_mes.pct_change()
print(len(r_mes), r_mes.index[0].date(), r_mes.index[-1].date())
r_mes.head(3).round(4)
```
```output
60 2021-01-31 2025-12-31
fecha
2021-01-31       NaN
2021-02-28    0.0173
2021-03-31    0.0576
Freq: ME, Name: cierre, dtype: float64
```

`"ME"` significa *month end*: la etiqueta de cada mes es su último día natural, aunque la última sesión fuera antes.
La rentabilidad de enero de 2021 es `NaN` porque no hay un mes anterior: los datos empiezan el 4 de enero. El alias
antiguo `"M"` ya no se admite en pandas 3.0:

```python raises
cierre.resample("M").last()
```
```output
ValueError: Invalid frequency: M. Failed to parse with error message: ValueError("'M' is no longer supported for offsets. Please use 'ME' instead.")
```

Componer las rentabilidades diarias de cada mes con `(1 + r).resample("ME").prod() - 1` da el mismo resultado. Lo
que no da lo mismo es la **media** de los cierres del mes: es otra serie, más suave, que no corresponde a ningún precio
al que se pudiera operar.

La etiqueta del periodo también importa. El valor de marzo de 2022 lleva la fecha del 31 de marzo y usa el cierre de
ese día: no se conoce hasta que termina el mes. Si después se cruza esta serie con datos diarios, el dato mensual solo
puede usarse a partir de la sesión siguiente. En una señal que se calcula «a principios de mes» con el dato del mes que
acaba de empezar se cuela la información de cuatro semanas futuras, y el backtest lo agradece de forma engañosa.
`resample` tiene los parámetros `label` y `closed` para elegir qué extremo del periodo da nombre a cada grupo; con
datos de precios, lo seguro es dejar los valores por defecto y desplazar con `shift(1)` lo que se vaya a usar como
señal.

## Agrupar: groupby

`groupby` sigue el patrón *dividir, aplicar, combinar*: separa las filas en grupos según una clave, aplica una función
a cada grupo y junta los resultados en una tabla con una fila por grupo. La clave puede ser una columna, un atributo
del índice o cualquier `Series` alineada:

```mermaid
flowchart TB
  A[Rentabilidades] --> B[Dividir por año]
  B --> C[Aplicar agg]
  C --> D[Tabla por año]
```

```python
por_ano = r.groupby(r.index.year).agg(["mean", "std", "count"])
por_ano["anual"] = (1 + r).groupby(r.index.year).prod() - 1
por_ano["vol_anual"] = por_ano["std"] * np.sqrt(252)
por_ano[["count", "anual", "vol_anual"]].round(4)
```
```output
       count   anual  vol_anual
fecha
2021     259  0.1520     0.1599
2022     260 -0.0850     0.2483
2023     260  0.1421     0.1495
2024     262  0.1432     0.1499
2025     261  0.0424     0.1792
```

2022 es el único año en negativo (−8,5 %) y el de mayor volatilidad (24,8 %, frente a un 15–18 % en los demás). La
columna `count` es un control rápido: 259 rentabilidades en 2021 porque la primera sesión no tiene anterior.

El mismo patrón con el día de la semana como clave es el primer paso de un estudio de estacionalidad:

```python
dias = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
semana = r.groupby(r.index.day_name()).agg(["mean", "count"])
semana = semana.reindex(dias)
semana["mean"] = (semana["mean"] * 100).round(3)
semana
```
```output
            mean  count
fecha
Monday     0.045    260
Tuesday   -0.052    261
Wednesday  0.019    261
Thursday   0.051    260
Friday     0.108    260
```

El viernes sale con la mayor media (0,108 % diario) y el martes en negativo. Antes de convertirlo en una regla, una
cuenta: el error típico de una media de 260 rentabilidades con una desviación típica del 1,14 % es
$0{,}0114 / \sqrt{260} \approx 0{,}07\ \%$. Las diferencias entre días son de ese orden: compatibles con el azar. En
SINT no puede haber efecto día de la semana, porque los datos se generan sin él; en datos reales, la misma tabla
produce «patrones» igual de convincentes y casi siempre igual de falsos (pruebas múltiples, nivel 2).

<aside class="callout" data-kind="nota">

`reindex(dias)` ordena las filas en el orden de la semana: `groupby` las devuelve ordenadas por la clave, y por orden
alfabético el viernes (*Friday*) iría primero. `day_name()` devuelve los nombres en inglés.

</aside>

## Pivotar: una tabla año × mes

`pivot` reorganiza una tabla larga (una fila por mes) en una tabla ancha: una fila por año, una columna por mes. Es la
tabla de rentabilidades mensuales que acompaña a cualquier informe de un fondo:

```python
larga = r_mes.to_frame("r").assign(
    ano=r_mes.index.year, mes=r_mes.index.month,
)
tabla = larga.pivot(index="ano", columns="mes", values="r")
(tabla * 100).round(1)
```
```output
mes    1    2     3    4    5    6    7     8    9    10   11   12
ano
2021  NaN  1.7   5.8  1.5 -5.0  7.2 -1.7   3.0  2.2  0.5 -3.5  6.6
2022 -3.6  8.4  -6.8 -9.9  7.2 -0.0 -3.9  10.9 -9.5 -3.1 -5.1  9.6
2023  2.6 -1.9   2.7  0.6  3.1 -0.4 -3.1   0.5  6.2 -0.5  2.4  1.5
2024  8.2 -1.9  -2.6  0.9  1.4  1.0  2.0  -5.4  7.3 -2.9 -0.9  7.4
2025  3.6  1.9 -10.1  5.6 -0.7 -2.1 -1.3   2.0  2.7  1.0  4.6 -2.1
```

Leída por filas, la tabla cuenta la historia de 2022: cinco meses con movimientos de más del 8 % en un sentido u otro,
de la caída del 9,9 % de abril a la subida del 10,9 % de agosto. Leída por columnas, sugiere tentaciones (¿diciembre
sube casi siempre?) con cinco datos por columna: demasiado pocos para concluir nada. Si la tabla larga tuviera dos filas con el mismo año y
mes, `pivot` lanzaría un error; `pivot_table` las agregaría con una función (por defecto, la media).

## Combinar tablas: merge y join

El libro de operaciones guarda fechas y precios de entrada, pero no el volumen de esos días ni cómo cerró el mercado.
`merge` combina dos tablas por columnas comunes, como el `JOIN` de SQL (lección 0.5.5). Para las operaciones de SINT,
la clave es la fecha de entrada en la izquierda y el índice de precios en la derecha:

```python
ops_sint = ops[ops["simbolo"] == "SINT"]
con_precio = ops_sint.merge(
    precios[["cierre", "volumen"]],
    left_on="fecha_entrada", right_index=True,
    how="left", validate="many_to_one",
)
print(len(ops_sint), len(con_precio))
iguales = (con_precio["precio_entrada"] == con_precio["cierre"]).all()
print("Entrada al cierre del día:", iguales)
con_precio[["id", "fecha_entrada", "lado", "cierre", "volumen"]].head(3)
```
```output
30 30
Entrada al cierre del día: True
   id fecha_entrada   lado  cierre  volumen
1   2    2021-09-02  largo  108.64  1454984
2   3    2021-10-27  corto  112.07  1644654
3   4    2021-11-10  corto  104.30  2575784
```

Tres controles en una celda. `how="left"` conserva todas las operaciones aunque falte su fecha en precios (saldría
`NaN`); `validate="many_to_one"` lanza un error si una fecha aparece dos veces en precios, que duplicaría operaciones en
silencio; y el número de filas antes y después debe coincidir: 30 y 30. La comparación final confirma lo que dice el
README de los datos: las entradas se hicieron al precio de cierre.

| Argumento | Valores | Para qué |
|---|---|---|
| `how` | `"inner"`, `"left"`, `"right"`, `"outer"` | Qué filas sin pareja se conservan |
| `on` / `left_on` / `right_on` | Columnas | Claves de cada lado |
| `left_index` / `right_index` | `True` | Usar el índice como clave |
| `validate` | `"one_to_one"`, `"many_to_one"`… | Error si la relación no es la esperada |
| `indicator` | `True` | Columna `_merge` con el origen de cada fila |

Cuando las dos tablas comparten el índice de fechas, `join` es más corto: une por índice y, por defecto, conserva las
filas de la izquierda. SINT y los cuatro activos de la cartera tienen el mismo calendario:

```python
cartera = pd.read_csv("cartera_sint.csv", parse_dates=["fecha"],
                      index_col="fecha")
todos = precios[["cierre"]].rename(columns={"cierre": "SINT"})
todos = todos.join(cartera)
print(todos.shape, todos.isna().sum().sum())
todos.pct_change().corr().round(2).loc["SINT"]
```
```output
(1303, 5) 0
SINT    1.00
RVAR   -0.01
RFIJ    0.00
ORO     0.00
TECH   -0.02
Name: SINT, dtype: float64
```

1.303 filas y ningún ausente: los calendarios coinciden. Con datos de dos mercados distintos no sería así, y la
decisión de qué hacer con las fechas sin pareja (lección 0.5.2) se toma aquí: `how="inner"` se queda con las sesiones
comunes, `how="outer"` con todas (y `NaN` donde falte un mercado), y `ffill()` arrastra el último precio conocido de un
mercado cerrado, que es lo que vería un gestor al valorar la cartera ese día. SINT apenas está correlacionado con los
activos de la cartera: son series ficticias generadas por separado.

## Ventanas: rolling y expanding

Una **ventana móvil** calcula un estadístico sobre las últimas n filas y avanza una fila cada vez. Es la herramienta de
las medias móviles, las volatilidades móviles y las bandas de cualquier indicador. La volatilidad anualizada de los
últimos 21 días (un mes de mercado) es:

$$
\sigma_t = \sqrt{252} \cdot \operatorname{std}(r_{t-20}, \dots, r_t)
$$

```python
vol_21 = r.rolling(21).std() * np.sqrt(252)
print(vol_21.isna().sum(), "valores sin ventana completa")
print(f"Mediana: {vol_21.median():.1%}")
print(f"Máxima:  {vol_21.max():.1%} el {vol_21.idxmax().date()}")
print(f"Mínima:  {vol_21.min():.1%} el {vol_21.idxmin().date()}")
```
```output
21 valores sin ventana completa
Mediana: 15.8%
Máxima:  33.9% el 2022-09-12
Mínima:  7.9% el 2021-11-03
```

La ventana está alineada a la derecha: el valor del 12 de septiembre de 2022 usa las 21 rentabilidades que terminan
ese día, incluida. Los 21 primeros valores son `NaN`: el primero porque no hay rentabilidad y los otros veinte porque
la ventana no está completa (con `min_periods` se puede pedir un cálculo con menos datos). El tamaño de la ventana
es un compromiso: con 21 sesiones la estimación reacciona en pocos días a un cambio de régimen, pero es ruidosa; con
63 o 126 es más estable y llega tarde. No hay una ventana correcta, y elegir la que mejor resultado da en un backtest es
otra forma de sobreajuste. La figura de la cabecera
dibuja esta serie: la volatilidad pasa largos periodos en torno a su mediana del 15,8 % y se dispara en dos episodios,
en 2022 y en abril de 2025, hasta duplicarla.

Una ventana **expansiva** (`expanding`) empieza en la primera fila y crece hasta la actual. Su uso más común en trading
es el máximo histórico de los precios, que define el **drawdown**: la caída desde el máximo alcanzado hasta ese momento.

$$
\text{DD}_t = \frac{P_t}{\max_{s \le t} P_s} - 1
$$

```python
maximo = cierre.expanding().max()
print((maximo == cierre.cummax()).all())
drawdown = cierre / maximo - 1
fondo = drawdown.idxmin()
pico = cierre.loc[:fondo].idxmax()
print(f"Peor drawdown: {drawdown.min():.1%}")
print(f"Del máximo del {pico.date()} al fondo del {fondo.date()}")
print(f"Sesiones en drawdown: {(drawdown < 0).mean():.0%}")
```
```output
True
Peor drawdown: -25.0%
Del máximo del 2022-03-07 al fondo del 2022-10-20
Sesiones en drawdown: 95%
```

`expanding().max()` y `cummax()` son lo mismo; `cummax` es más corto. El peor drawdown de SINT es del 25 %: del máximo
de marzo de 2022 al fondo de octubre. Y el 95 % de las sesiones está por debajo del máximo previo: lo normal en un
activo, o en una estrategia, es estar en drawdown. La lección 0.6.1 dibuja esta curva bajo los precios.

<aside class="callout" data-kind="riesgo">

`rolling` y `expanding` solo usan el pasado, pero es fácil romperlo. `rolling(21, center=True)` centra la ventana y usa
diez sesiones futuras; `shift(-1)` trae el dato de mañana a la fila de hoy; normalizar con la media y la desviación de
**toda** la serie usa el futuro en cada punto. En un indicador para una figura no pasa nada; en una señal, es
anticipación (*look-ahead*) y el backtest sale mejor de lo que será en real. Si una señal usa la volatilidad de hoy,
opera como pronto al cierre de hoy o con `shift(1)` al día siguiente.

</aside>

## Ejercicios

1. Construye las barras **semanales** de SINT (apertura, máximo, mínimo, cierre y volumen) con `resample("W-FRI")` y
   `agg`, con la agregación correcta para cada columna. Muestra las tres primeras.

**Solución.**

```python
semanal = precios.resample("W-FRI").agg({
    "apertura": "first", "maximo": "max", "minimo": "min",
    "cierre": "last", "volumen": "sum",
})
print(len(semanal))
semanal.head(3)
```
```output
261
            apertura  maximo  minimo  cierre   volumen
fecha
2021-01-08    100.02  100.64   97.22   99.05  10647985
2021-01-15     98.98   99.70   96.96   97.75   7135061
2021-01-22     97.68   99.32   96.02   98.36   7573689
```

La apertura de la semana es la del primer día; el cierre, el del último; el máximo y el mínimo, los extremos de la
semana; el volumen, la suma. `"W-FRI"` cierra las semanas en viernes y las etiqueta con esa fecha.

2. Calcula el resultado neto de cada operación del libro (signo × diferencia de precios × cantidad − comisión) y, con
   `groupby`, una tabla por símbolo con el número de operaciones, el resultado total y el porcentaje de ganadoras.

**Solución.**

```python
signo = np.where(ops["lado"] == "largo", 1, -1)
ops["pnl"] = (signo * (ops["precio_salida"] - ops["precio_entrada"])
              * ops["cantidad"] - ops["comision"])
resumen = ops.groupby("simbolo").agg(
    operaciones=("pnl", "size"),
    total=("pnl", "sum"),
    ganadoras=("pnl", lambda s: (s > 0).mean()),
)
resumen.round(2)
```
```output
         operaciones    total  ganadoras
simbolo
ORO                3 -3237.96       0.00
RVAR               4    17.09       0.50
SINT              30  4405.08       0.63
TECH               3   -35.02       0.33
```

La sintaxis `nombre=(columna, función)` de `agg` pone nombre a cada columna del resultado. El porcentaje de ganadoras
es la media de una máscara de `bool`. Con tres o cuatro operaciones por símbolo fuera de SINT, ninguna de estas cifras
dice nada sobre la calidad de las reglas que las generaron.

3. ¿Cuántas sesiones de cada año tuvieron una volatilidad de 21 sesiones por encima del 25 %? Usa `vol_21` y `groupby`.

**Solución.**

```python
alta = vol_21 > 0.25
alta.groupby(alta.index.year).sum()
```
```output
fecha
2021      0
2022    133
2023      0
2024      0
2025     31
Name: cierre, dtype: int64
```

Sumar una máscara cuenta los `True`. La mayoría de las sesiones de volatilidad alta están en 2022; el repunte de 2025
es más corto. Los `NaN` del principio cuentan como `False` en la comparación (lección 0.5.1), así que no suman.

## Autoevaluación

1. `precios` tiene un `DatetimeIndex`. ¿Qué devuelve `precios.iloc[-1, 3]`?

   - A. La fila con etiqueta −1 y la columna con etiqueta 3
   - B. El valor de la última fila y la cuarta columna, por posición
   - C. Un error, porque el índice es de fechas
   - D. Las tres últimas filas

   *Respuesta B: El valor de la última fila y la cuarta columna, por posición.* `iloc` usa posiciones, empezando en 0, como las listas de Python: −1 es la última fila y 3, la cuarta columna. `loc` usaría etiquetas (fechas y nombres de columna).

2. ¿Cuál de estas expresiones filtra las sesiones con caída mayor del 3 % y volumen por encima de la mediana?

   - A. `p[r < -0.03 and p["volumen"] > med]`
   - B. `p[(r < -0.03) & (p["volumen"] > med)]`
   - C. `p[r < -0.03 & p["volumen"] > med]`
   - D. `p[(r < -0.03) or (p["volumen"] > med)]`

   *Respuesta B: `p[(r < -0.03) & (p["volumen"] > med)]`.* Con máscaras de pandas se usan `&`, `|` y `~`, no `and`/`or`, y cada condición va entre paréntesis porque `&` tiene más prioridad que `<` y `>`.

3. `r.rolling(21).std()` en la fecha t, ¿qué rentabilidades usa?

   - A. Las 21 sesiones centradas en t
   - B. Las 21 sesiones siguientes a t
   - C. Las 21 sesiones que terminan en t, incluida t
   - D. Todas las sesiones hasta t

   *Respuesta C: Las 21 sesiones que terminan en t, incluida t.* Por defecto la ventana está alineada a la derecha: termina en la fila actual. Con `center=True` usaría sesiones futuras, y `expanding()` usaría todas las anteriores.

4. Al combinar operaciones con precios por fecha, ¿para qué sirve `validate="many_to_one"` en `merge`?

   - A. Para eliminar las operaciones duplicadas
   - B. Para lanzar un error si una fecha aparece más de una vez en la tabla de precios, en lugar de duplicar operaciones en silencio
   - C. Para que el merge sea más rápido
   - D. Para conservar solo las fechas comunes

   *Respuesta B: Para lanzar un error si una fecha aparece más de una vez en la tabla de precios, en lugar de duplicar operaciones en silencio.* Si la tabla de la derecha tuviera dos filas con la misma fecha, cada operación de ese día se duplicaría y el resultado total cambiaría sin avisar. `validate` convierte ese error de datos en una excepción.

## Ideas clave

- `loc` selecciona por etiqueta (fechas y nombres) con los extremos incluidos; `iloc`, por posición. Las máscaras se combinan con `&`, `|` y `~`, cada condición entre paréntesis.
- `resample("ME")` cambia de frecuencia por fecha; `groupby` agrupa por cualquier clave (año, día de la semana, símbolo) y aplica una agregación a cada grupo.
- `merge` combina tablas por columnas y `join`, por índice. `validate` y `indicator` detectan duplicados y filas sin pareja antes de que falseen un resultado.
- `rolling(n)` usa las n filas que terminan en la actual y `expanding()` todas las anteriores: ninguna mira al futuro. `center=True` sí, y no se usa para señales.
- Volatilidad móvil: `r.rolling(21).std() * np.sqrt(252)`. Drawdown: `cierre / cierre.cummax() - 1`.

## Recursos

### Research

- [Estimadores de volatilidad](https://pythonparatrading.com/estimadores-de-volatilidad-para-trading/) · Research-0002 · 4 min

### Documentación

- [pandas: indexado y selección de datos (guía de usuario)](https://pandas.pydata.org/docs/user_guide/indexing.html) · pandas.pydata.org
- [pandas: group by, split-apply-combine (guía de usuario)](https://pandas.pydata.org/docs/user_guide/groupby.html) · pandas.pydata.org
- [pandas: merge, join y concat (guía de usuario)](https://pandas.pydata.org/docs/user_guide/merging.html) · pandas.pydata.org
- [pandas: operaciones de ventana (guía de usuario)](https://pandas.pydata.org/docs/user_guide/window.html) · pandas.pydata.org

### Datos

- [Datos del nivel 0: barras diarias de SINT (CSV)](https://pythonparatrading.com/curso/datos/nivel-0/sint_diario.csv) · Descarga · sint_diario.csv

Lección anterior: [0.5.2 · pandas 3.0: Series, DataFrame, índices temporales, Copy-on-Write, tipo str y pd.col()](https://pythonparatrading.com/curso-python-trading/nivel-0/pandas-3-series-y-dataframe/)

Lección siguiente: [0.5.4 · Polars: API lazy frente a eager, expresiones, rendimiento y cuándo elegirlo frente a pandas](https://pythonparatrading.com/curso-python-trading/nivel-0/polars-lazy-y-expresiones/)
