Lesson 2 of 21· Introducción: por qué Polars
Si vienes de DA-201, pandas ya es tu navaja suiza: cargas un CSV, limpias columnas, agrupas, unes tablas y exportas un resultado. Para muchos análisis de unos pocos miles de filas, pandas es perfecto y no hay razón para tocarlo.
El problema aparece cuando los datos crecen. Llega el día en que un groupby tarda minutos, un merge agota la memoria del portátil, o un pipeline que corría en segundos sobre 100.000 filas se arrastra durante media hora sobre 50 millones. Ahí es donde el diseño interno de pandas empieza a pasar factura.
Polars no es "pandas pero más rápido por arte de magia": es una arquitectura distinta que ataca, una por una, las limitaciones estructurales de pandas. Esta lección es conceptual a propósito: antes de escribir una sola expresión de Polars, conviene entender por qué es más rápido. Así sabrás cuándo te dará una ventaja real y cuándo no merece la pena migrar.
Las razones por las que pandas se queda corto no son bugs ni mala programación: son consecuencias directas de decisiones de diseño tomadas hace más de quince años, cuando los conjuntos de datos eran pequeños y los procesadores tenían un solo núcleo rápido.
pandas es eager: cada operación se ejecuta en el instante en que la escribes. Cuando encadenas varias transformaciones, pandas no ve la consulta completa; ejecuta cada línea de forma aislada y materializa un resultado intermedio en memoria tras cada paso.
# pandas ejecuta esto en 3 pasos independientes,
# creando 2 DataFrames intermedios que se descartan
df2 = df[df["pais"] == "ES"] # 1) filtra TODAS las columnas
df3 = df2.assign(iva=df2["precio"] * 0.21) # 2) crea columna
resultado = df3[["pedido_id", "iva"]] # 3) y al final tira casi todoNadie le dice a pandas que al final solo necesitas dos columnas. Por eso filtra y copia las 40 columnas del DataFrame, aunque 38 acaben en la basura. No hay un optimizador que reordene el trabajo para hacer menos.
La mayoría de las operaciones de pandas corren en un único hilo. Tu portátil tiene 8 o 16 núcleos, pero durante un groupby pesado 15 de ellos están de brazos cruzados mientras uno solo suda. pandas fue diseñado en una época en la que esto no importaba; hoy es desperdiciar la mayor parte de la máquina.
Un DataFrame de pandas es, en esencia, una colección de arrays de NumPy más un índice (el famoso Index). Ese diseño tiene tres costes:
NaN, las columnas de enteros se promueven a float64; las cadenas de texto se guardan como object, es decir, un array de punteros a objetos Python dispersos por la memoria — lento de recorrer y pesado.reset_index, alineaciones inesperadas, SettingWithCopyWarning).Una base de datos SQL, antes de ejecutar tu consulta, la planifica: empuja los filtros lo más pronto posible, descarta columnas que no se usan, reordena los joins. pandas no hace nada de esto. Ejecuta literalmente lo que escribiste, en el orden en que lo escribiste, aunque haya un camino mucho más barato para el mismo resultado.
Polars reconstruye el DataFrame desde cero con tecnología moderna, atacando exactamente esos cuatro puntos:
group_by usa toda la máquina.Ese último punto convierte el ejemplo anterior en algo radicalmente más eficiente: si Polars ve que al final solo quieres pedido_id e iva, leerá y procesará únicamente esas columnas desde el principio. Es la diferencia entre cargar un camión entero para entregar dos cajas, o cargar solo las dos cajas. Lo veremos a fondo en el Módulo 3.
El siguiente diagrama resume la diferencia de fondo. A la izquierda, pandas: arrays de NumPy pegados a un índice, ejecutados de inmediato en un solo hilo. A la derecha, Polars: columnas Arrow que pasan por un motor de consultas en Rust capaz de optimizar y paralelizar.
| Aspecto | pandas | Polars |
|---|---|---|
| Lenguaje del motor | Python + C (NumPy/Cython) | Rust nativo |
| Modelo de datos | Arrays NumPy + un Index | Columnas Apache Arrow, sin índice |
| Texto y nulos | object (punteros) y enteros promovidos a float64 | Tipo Arrow nativo, nulos sin cambiar el tipo |
| Ejecución | Eager: operación a operación | Eager y lazy (a elección) |
| Optimizador de consultas | No | Sí (en modo lazy) |
| Paralelismo | Mayormente 1 hilo | Multinúcleo por defecto |
| Mayor que la memoria | No (cabe todo en RAM o falla) | Sí, vía streaming (Módulo 3) |
| Madurez del ecosistema | Enorme, 15+ años | Joven pero creciendo muy rápido |
Fíjate en la última fila: pandas no desaparece. Su ecosistema (integraciones, tutoriales, librerías que lo esperan como entrada) sigue siendo el más amplio. La cuestión nunca es "pandas está roto", sino "para este trabajo, ¿qué arquitectura encaja mejor?". Esa decisión la afinaremos en el Módulo 5.
Las cifras dependen del hardware y de la operación, pero el patrón es consistente: en cargas con agregaciones y joins sobre millones de filas, Polars suele ser varias veces más rápido que pandas y consumir bastante menos memoria, gracias al paralelismo, al formato columnar y (en lazy) al optimizador. La siguiente gráfica es ilustrativa del orden de magnitud de la ventaja en un group_by pesado — en el Módulo 5 lo mediremos tú y yo con timeit sobre datos reales, sin creernos los números de nadie.
Antes de seguir, verifica que identificas correctamente qué limitación de pandas explica cada escenario:
Free