Skip to content

Cómo actualizar a pandas 3.1: corregir el Pandas4Warning de inplace, usar df.select() y pd.col(), y leer CSV más rápido

Actualizado el

pandas 3.1.0 (22 de octubre de 2026) marca inplace=True como obsoleto en drop, rename, sort_values y ocho métodos más, añade DataFrame.select() con expresiones pd.col() y filter(cond=), y lee CSV grandes en paralelo. Probado en macOS: un CSV de 72 MB pasó de 0,23 s a 0,02 s, la lista exacta de Pandas4Warning, las opciones de read_csv que desactivan el lector paralelo sin avisar y la trampa de NumPy 2.3.3 en Python 3.14.

La respuesta corta: pandas 3.1.0 salió el 22 de octubre de 2026, y la versión correctiva 3.1.1 llegó el 4 de noviembre. Actualiza directamente a 3.1.1:

pip install --upgrade "pandas>=3.1"
# or, in a uv project
uv add "pandas>=3.1"

Después de actualizar van a pasar tres cosas:

  1. Tu código imprime Pandas4Warning por cada inplace=True en drop, rename, reset_index, set_index, sort_values, dropna, drop_duplicates y algunos más. La corrección es mecánica: df = df.drop(...) en lugar de df.drop(..., inplace=True). Muchas veces el aviso viene de una librería que usas, no de tu código.
  2. pd.read_csv con archivos locales grandes es mucho más rápido. Un archivo de 72 MB pasó de 0,23 s en pandas 3.0.1 a 0,02 s en 3.1 en nuestra prueba. Algunos argumentos habituales desactivan la mejora; están listados más abajo.
  3. Tienes una API al estilo Polars: df.select("a", pd.col("b") * 2) y df.filter(pd.col("a") > 1).

Si todavía estás en pandas 2.x, el salto a 3.x (Copy-on-Write, el dtype de cadena por defecto) es el cambio grande, y la guía de migración a pandas 3.0 (opens in a new tab) es el punto de partida. Esta guía cubre 3.0 → 3.1 y las trampas con las que nos topamos.

Qué se probó: todo lo marcado como "probado" se ejecutó el 1 de noviembre de 2026 en un Apple M4 Max (16 núcleos, macOS) en un entorno virtual uv limpio con CPython 3.14.2, pandas 3.1.0, NumPy 2.5.4 y PyArrow 26.0.0. Los números de comparación vienen de pandas 3.0.1 con NumPy 2.4.2 y sin PyArrow en la misma máquina. El comportamiento en Windows, Linux, conda y Docker se basa en la documentación oficial y no se probó aquí. El 4 de noviembre de 2026 se volvió a ejecutar cada afirmación probada con pandas 3.1.1, con los mismos resultados.

Qué cambia en 3.1 y vas a notar

CambioQué significa para tiAcción
inplace obsoleto en 11 métodos (PDEP-8)Cada llamada emite un Pandas4Warning; se eliminará en pandas 4.0Reasigna el resultado: df = df.drop(...)
read_csv paralelo para archivos locales sin comprimir ≥ 5 MB2–3x más rápido en un solo hilo, más hasta 6 hilos por defectoNada, salvo que pases usecols, index_col, nrows o un descriptor de archivo (ver abajo)
DataFrame.select() (acepta expresiones pd.col(), disponibles desde 3.0)Selecciona y calcula columnas en una sola llamada, al estilo PolarsOpcional; útil en cadenas de métodos
filter(cond=...) acepta una máscara booleanadf.filter(pd.col("a") > 1) conserva filasCuidado: una lista posicional de booleanos sigue seleccionando etiquetas
NumPy ≥ 2.0.2 obligatorio (≥ 2.3.3 en Python 3.14)Los entornos con NumPy 1.x no pueden instalar 3.1Actualiza NumPy primero, o fija pandas<3.1
La entrada numérica usa microsegundos por defectopd.to_timedelta([1], unit="s") ahora es timedelta64[us], no [s]Corrige un error de redondeo de 3.0; usa .as_unit() si necesitas una resolución concreta
dtype="category" en read_csv infiere categorías numéricasLos códigos postales y los IDs pierden los ceros inicialesLee esas columnas primero como str

La lista completa está en el What's new in 3.1.0 oficial (opens in a new tab). El resto de esta guía recorre las tareas en orden: instalar, corregir los avisos, usar la API nueva, acelerar la carga de CSV y revisar los cambios de comportamiento que pueden alterar resultados sin lanzar ningún error.

Paso 1: instalar pandas 3.1

Requisitos (probado)

pandas 3.1.0 publica wheels para CPython 3.11 a 3.15 (requires_python >= 3.11) y está tanto en PyPI como en conda-forge. El mínimo de NumPy depende de tu versión de Python:

PythonNumPy mínimo
3.11 – 3.132.0.2
3.14 – 3.152.3.3

La página de whatsnew solo menciona 2.0.2. En Python 3.14 los metadatos del wheel piden 2.3.3, que es lo que el resolutor exige. Fijar NumPy 1.x falla directamente:

  × No solution found when resolving dependencies:
  ╰─▶ Because pandas==3.1.1 depends on numpy>=2.3.3 and you require
      pandas==3.1.1, we can conclude that you require numpy>=2.3.3.
      And because you require numpy<2, we can conclude that your requirements
      are unsatisfiable.

Si una dependencia todavía fija numpy<2, es esa dependencia la que bloquea la actualización, no pandas. Actualízala o mantén pandas<3.1 hasta que lo haga.

Actualizar (probado con uv)

Instala 3.1.1, no 3.1.0: 3.1.1 corrige una regresión por la que read_csv y to_csv trataban objetos de ruta como el tmpdir de pytest como descriptores de archivo abiertos y podían lanzar un error o escribir archivos incompletos (What's new in 3.1.1 (opens in a new tab)).

# pip
pip install --upgrade "pandas>=3.1,<3.2"
 
# uv project
uv add "pandas>=3.1,<3.2"
 
# uv, throwaway environment to test first
uv venv p31 --python 3.14
uv pip install --python p31/bin/python "pandas==3.1.1" pyarrow
p31/bin/python -c "import pandas as pd; print(pd.__version__)"

conda-forge tiene 3.1.1 (comprobado el 4 de noviembre de 2026; conda install -c conda-forge "pandas>=3.1"), no probado aquí.

Instala también PyArrow si aún no lo tienes. pandas 3 lo usa para el dtype de cadena por defecto cuando está presente, y el lector CSV con engine="pyarrow" lo necesita.

Paso 2: corregir el Pandas4Warning de inplace

Después de actualizar, un código como este:

df.drop(columns=["rain"], inplace=True)

imprime:

Pandas4Warning: The inplace keyword in DataFrame.drop is deprecated and will be removed in a future version (PDEP-8).
See https://pandas.pydata.org/docs/dev/whatsnew/v3.1.0.html#deprecation-inplace for more details.

Qué métodos están afectados (probado)

La deprecación cubre los métodos en los que inplace=True nunca cambió los valores en el sitio. En dropna, sort_values y los demás métodos que reordenan filas siempre fue una reasignación, y la copia que drop, rename o set_index evitaban antes ya no se produce de todos modos con Copy-on-Write, que llegó en pandas 3.0.

Métodoinplace en 3.1Corrección
drop, rename, rename_axisObsoletodf = df.drop(...)
reset_index, set_indexObsoletodf = df.reset_index()
sort_values, sort_indexObsoletodf = df.sort_values("col")
dropna, drop_duplicatesObsoletodf = df.dropna()
eval, queryObsoletodf = df.query("a > 1")
fillna, replace, where, mask, clip, interpolateSe mantiene (pueden actualizar valores en el sitio)No hace falta cambiar nada

En nuestra prueba, los 11 métodos obsoletos avisaron al llamarlos con inplace=True; fillna y replace no, tal como está documentado.

El reemplazo es un cambio de una línea por llamada:

# before
df.rename(columns={"temp": "temp_c"}, inplace=True)
df.sort_values("temp_c", inplace=True)
df.reset_index(drop=True, inplace=True)
 
# after (same cost, chains cleanly)
df = (
    df.rename(columns={"temp": "temp_c"})
      .sort_values("temp_c")
      .reset_index(drop=True)
)

Encontrar todas las llamadas en tu código (probado)

Convierte el aviso en error durante una ejecución y el traceback te señala la línea exacta. python -W no acepta una clase de terceros como pandas.errors.Pandas4Warning: imprime Invalid -W option ignored: invalid module name: 'pandas.errors' y ejecuta el script de todos modos. Filtra por el mensaje en su lugar:

python -W "error:The inplace keyword:DeprecationWarning" your_script.py

Para convertir en error cualquier Pandas4Warning, no solo los de inplace:

python -c "import runpy, warnings, pandas as pd; warnings.simplefilter('error', pd.errors.Pandas4Warning); runpy.run_path('your_script.py', run_name='__main__')"

Ambos terminan con un traceback en la primera línea con inplace. El filtro por mensaje no toca los demás avisos de deprecación.

Para una suite de tests, pytest aplica sus filtros -W cuando pandas ya se puede importar, así que ahí el nombre de la clase sí funciona:

pytest -W error::pandas.errors.Pandas4Warning

Pandas4Warning es una subclase de PandasDeprecationWarning, así que un filtro sobre cualquiera de las dos funciona. Un grep también te lleva casi hasta el final:

grep -rn "inplace=True" --include="*.py" --include="*.ipynb" .

Cuando el aviso viene de una librería, no de ti

Es el caso habitual en las primeras semanas tras una versión nueva. Entre el 22 de octubre y el 1 de noviembre de 2026, GitHub sumó unos 300 issues y pull requests que mencionan Pandas4Warning y unos 3500 que mencionan "pandas 3.1", en proyectos como yfinance (29 llamadas inplace en 8 archivos, yfinance #3009 (opens in a new tab); corregido en yfinance 1.8.0 el 3 de noviembre), FLAML, marimo, cuDF, darts y category_encoders.

Eso no lo puedes corregir desde tu código. Opciones, por orden de preferencia:

  1. Actualiza la librería. Muchas publicaron la corrección en cuestión de días.
  2. Silencia solo esta clase de aviso hasta que la librería se ponga al día, en lugar de silenciar todos los avisos:
import warnings
import pandas as pd
 
warnings.filterwarnings("ignore", category=pd.errors.Pandas4Warning)
  1. Fija pandas<3.1 en el entorno que ejecuta la librería sin mantenimiento. No fijes pandas 3.0 para siempre; la palabra clave inplace se eliminará en 4.0 y el aviso es tu periodo de preaviso.

Otras deprecaciones con las que puedes toparte en 3.1 (probado salvo que se indique)

Código que ahora avisaReemplazo
s.dt.dayofweek, .dayofyear, .daysinmonths.dt.day_of_week, .day_of_year, .days_in_month
df.select_dtypes(include="object") en columnas de cadena (ya avisaba en 3.0; 3.1 añade exclude="object")Pasa "str" de forma explícita; "object" ya no significa "texto" en pandas 3
s.fillna("missing") en una columna floatConvierte primero a un dtype común; esto lanzará un error en una versión futura
ser.values en una columna con zona horariaser.array, ser.to_numpy(), o ser.dt.tz_convert(None).to_numpy() para conservar el array UTC antiguo
pd.infer_freq(idx) devolviendo "D"Devolverá un objeto offset; usa .freqstr o define future.infer_freq_returns_offset
read_parquet(engine="fastparquet") (docs)fastparquet está retirado; usa el motor PyArrow por defecto
pd.set_eng_float_format() (docs)pd.set_option("display.precision", n)

Paso 3: usar df.select(), pd.col() y filter(cond=)

DataFrame.select() y filter(cond=) son la API nueva visible en 3.1. pd.col() en sí llegó en pandas 3.0 para assign() y .loc; en 3.1 pasa a ser el argumento natural de los dos métodos nuevos. Si has usado Polars, te resultarán familiares.

select selecciona y calcula columnas en una sola llamada (probado)

import pandas as pd
 
df = pd.DataFrame({
    "city": ["Tokyo", "Seoul", "Osaka"],
    "temp": [18.2, 15.1, 19.5],
    "rain": [12, 30, 8],
})
 
df.select("city", "temp")                         # same as df[["city", "temp"]]
df.select("city", temp_f=pd.col("temp") * 1.8 + 32)   # keyword names the new column
    city  temp_f
0  Tokyo   64.76
1  Seoul   59.18
2  Osaka   67.10

Los argumentos posteriores pueden referirse a columnas creadas antes en la misma llamada, como en assign:

df.select(temp_c=pd.col("temp"), temp_f=pd.col("temp_c") * 1.8 + 32)

pd.col("temp") es un pandas.api.typing.Expression. Admite los operadores y accesores que usarías sobre una Series, incluidos .str y .round():

df.select(pd.col("city").str.upper(), pd.col("temp").round(0))

Tres cosas que nos hicieron tropezar (probado):

  • No hay .alias(). Nombra una columna calculada con la forma de palabra clave (temp_f=...). pd.col("temp").alias("x") se construye sin quejarse, pero luego df.select(...) falla con AttributeError: 'Series' object has no attribute 'alias'.
  • Una expresión que se reduce a un escalar, como pd.col("temp").mean(), debe pasarse como palabra clave (mean_temp=pd.col("temp").mean()); entonces se propaga a todas las filas. Pasada de forma posicional lanza TypeError.
  • Una columna inexistente lanza KeyError, igual que df[["nope"]].

filter(cond=) conserva filas con una máscara booleana (probado)

DataFrame.filter antes solo seleccionaba etiquetas (items=, like=, regex=). En 3.1 también acepta una máscara:

df.filter(cond=df["temp"] > 17)          # a boolean Series
df.filter(pd.col("temp") > 17)           # an expression, positional is fine
df.filter(lambda d: d["rain"] < 20)      # a callable

Encadenado, se lee como Polars sin dejar de ser un DataFrame de pandas:

(
    df.filter(pd.col("rain") < 20)
      .select("city", "temp")
      .sort_values("temp")
)

Los valores faltantes en la máscara cuentan como False por defecto; pasa na=True para conservarlos o na="raise" para que lance un error.

La trampa: una lista simple de booleanos pasada de forma posicional sigue yendo por la ruta de etiquetas. En nuestra prueba, df.filter([True, False, True]) devolvió un DataFrame con cero columnas y un UserWarning que nos indicaba usar cond=. Escribe siempre cond= cuando la máscara sea una lista o un array.

Polars y pandas 3.1 lado a lado

TareaPolarspandas 3.1
Seleccionar columnasdf.select("a", "b")df.select("a", "b")
Calcular una columnadf.select(pl.col("a") * 2)df.select(pd.col("a") * 2)
Nombrarla(pl.col("a") * 2).alias("a2")df.select(a2=pd.col("a") * 2)
Filtrar filasdf.filter(pl.col("a") > 1)df.filter(pd.col("a") > 1)
Agregardf.select(pl.col("a").mean()) → 1 filadf.select(m=pd.col("a").mean()) → se propaga a todas las filas

pandas no se está convirtiendo en Polars: no hay evaluación perezosa ni optimizador de consultas detrás de select. Es sintaxis que hace legibles las cadenas y te evita repetir el nombre del DataFrame. Si te planteas cambiar de motor, Polars vs pandas cubre esa decisión.

Paso 4: conseguir el read_csv más rápido, y saber qué lo desactiva

El benchmark (probado)

Un archivo: 3 000 000 filas × 3 columnas (float, int, cadena), 72,5 MB, sin comprimir, en SSD local. Mejor de tres ejecuciones.

LectorTiempovs pandas 3.0.1
pandas 3.0.1, engine="c"0,233 s1x
pandas 3.1.0, mode.max_threads = 1 (serie)0,089 s2,6x
pandas 3.1.0, 2 hilos0,049 s4,8x
pandas 3.1.0, 4 hilos0,025 s9,3x
pandas 3.1.0, por defecto (6 hilos)0,018 s13x
pandas 3.1.0, engine="pyarrow"0,030 s7,8x

La fila en serie coincide con las notas de la versión ("dos a tres veces más rápido"); las filas en paralelo se suman a eso. Tu archivo será distinto (más columnas de cadena se parsean más lento), pero la forma del resultado es lo importante: el lector engine="c" por defecto ahora es más rápido que PyArrow para un archivo local normal.

Las condiciones (docs, confirmadas por los tiempos de arriba)

La ruta paralela se activa automáticamente cuando se cumplen todas estas condiciones:

  • filepath_or_buffer es una ruta a un archivo local sin comprimir
  • se usa el motor C por defecto
  • las filas de datos suman al menos 5 MB
  • mode.max_threads es mayor que 1 (por defecto: número de CPUs, con tope en 6, y 1 cuando el proceso está limitado a una CPU)
  • ninguna opción que necesite el archivo completo de una vez: iterator, chunksize, nrows, usecols, index_col, parse_dates, un skiprows de tipo lista o callable, cabeceras de varias filas, o una codificación distinta de UTF-8

Cualquier otro caso cae en el lector en serie, y el resultado siempre es idéntico al de una lectura en serie.

Cómo se vio en nuestra prueba (probado)

LlamadaTiempo¿Paralelo?
pd.read_csv("big.csv")0,018 ssí
pd.read_csv("big.csv", usecols=["a", "c"])0,079 sno
pd.read_csv("big.csv", index_col=0)0,091 sno
pd.read_csv("big.csv", nrows=1_000_000)0,032 sno (en serie, un tercio del archivo)
pd.read_csv("big.csv", converters={"b": int})0,255 sno (más lento que una lectura simple, pero aún más rápido que la misma llamada en 3.0)
pd.read_csv(open("big.csv", "rb"))0,091 sno (descriptor de archivo, no una ruta)
pd.read_csv(io.StringIO(text))0,131 sno
pd.read_csv("big.csv.gz")0,163 sno (comprimido)
pd.concat(pd.read_csv("big.csv", chunksize=500_000))0,099 sno
pd.read_csv("big.csv", dtype={...})0,034 ssí (un dtype explícito no molesta)
pd.read_csv("big.csv", na_values=["z"])0,025 ssí

Dos consecuencias prácticas:

  • usecols ahora puede hacer una lectura más lenta, no más rápida. Durante años el consejo fue "pasa usecols para saltarte las columnas que no necesitas". En un archivo local ≥ 5 MB con 3.1, leer todo en paralelo y descartar columnas después fue 4x más rápido que usecols en nuestra prueba. Mide antes de conservar la costumbre.
  • Pasa una ruta, no un descriptor. pd.read_csv("file.csv") es paralelo; pd.read_csv(open("file.csv")) no. Los wrappers que entregan a pandas un objeto de archivo abierto en lugar de una ruta pierden la mejora.

Bajar el paralelismo dentro de una aplicación ya paralela

Si pandas corre dentro de Dask, Ray, un pool de multiprocessing o un worker web que ya usa todos los núcleos, limita los hilos para que no compitan entre sí:

import pandas as pd
 
with pd.option_context("mode.max_threads", 1):
    df = pd.read_csv("large.csv")
 
# or globally
pd.set_option("mode.max_threads", 2)

En Docker y Kubernetes el tope sigue la cuota de CPU del cgroup (docs, no probado aquí), así que un contenedor limitado a una CPU lee en serie sin que hagas nada.

Paso 5: revisar los cambios de comportamiento que no lanzan errores

Estos son los cambios con más probabilidad de alterar un resultado en silencio. Cada uno se reprodujo en 3.0.1 y 3.1.0 (probado).

Timedelta y datetime a partir de números ahora usan microsegundos por defecto

En 3.0, pd.to_timedelta([1], unit="s") producía timedelta64[s], y la aritmética conservaba esa resolución. Al dividirlo, redondeaba a segundos enteros:

td = pd.to_timedelta([1], unit="s")
print(td / 3)
# pandas 3.0.1 → TimedeltaIndex(['0 days'], dtype='timedelta64[s]', freq=None)
# pandas 3.1.x → TimedeltaIndex(['0 days 00:00:00.333333'], dtype='timedelta64[us]', freq=None)

3.1 lo corrige usando microsegundos por defecto, sea cual sea el unit con el que conviertas. Si tu código comparaba dtypes o dependía de la resolución [s], usa .as_unit("s") de forma explícita. Timestamp y to_datetime con entrada numérica cambiaron del mismo modo.

Relacionado: Timedelta.total_seconds() ahora incluye los nanosegundos. pd.Timedelta(nanoseconds=1500).total_seconds() devuelve 1.5e-06 en lugar de 1e-06.

dtype="category" en read_csv infiere categorías numéricas

from io import StringIO
data = "zip\n00501\n00501\n10001"
 
pd.read_csv(StringIO(data), dtype="category")["zip"].cat.categories.tolist()
# pandas 3.0.1 → ['00501', '10001']
# pandas 3.1.0 → [501, 10001]        leading zeros gone

El motor C ahora hace lo que el motor PyArrow ya hacía. Para códigos postales, números de cuenta y cualquier identificador con ceros a la izquierda, lee la columna como str y convierte después:

df = pd.read_csv("file.csv", dtype={"zip": "str"})
df["zip"] = df["zip"].astype("category")

Cosas que antes pasaban en silencio y ahora lanzan errores

  • pd.Timestamp(datetime(2020, 12, 31), hour=5) lanzó ValueError en nuestra prueba; en 3.0 ignoraba hour sin avisar. Pasa todos los componentes como palabras clave.
  • pd.to_timedelta("3:25:00 PM") lanza un error; 3.0 lo interpretaba como tres horas y descartaba el PM.
  • La aritmética de DataFrame y las comparaciones de orden con una Series category a lo largo del axis="columns" por defecto (por ejemplo df + cat_series) ahora lanzan TypeError en lugar de operar sobre las categorías; la igualdad no cambia (docs, reproducido).
  • Index.values e Index.array devuelven arrays de solo lectura, así que el código que mutaba un índice a través de ellos ahora falla de forma visible en lugar de corromper las búsquedas (docs).

Regex en cadenas respaldadas por PyArrow (probado)

Con PyArrow instalado, \w, \d, \s, \b en .str.replace, .str.count y similares solo coincidían con ASCII en pandas 3.0. En 3.1 vuelven a coincidir con Unicode, en línea con el re de Python y con pandas 2.x. Con PyArrow 26.0.1, pd.Series(["héllo wörld", "naïve 東京"]).str.count(r"\w") devolvió [8, 4] en pandas 3.0.6 y [10, 7] en 3.1.1. Si procesas texto no inglés y viste caer los conteos al pasar a 3.0, esta es la corrección. 3.1.1 también corrige que \s no coincidiera con \x0b ni con \x1c en cadenas de PyArrow.

¿Deberías actualizar ya?

SituaciónRecomendación
Proyecto nuevo, Python 3.11+Sí. Empieza en 3.1 y escribe sin inplace
Scripts y notebooks en 3.0Sí. Ejecuta una vez con -W "error:The inplace keyword:DeprecationWarning" (o pytest -W error::pandas.errors.Pandas4Warning), corrige las líneas y quédate con las lecturas CSV más rápidas
Librería o pipeline que carga IDs con ceros iniciales con dtype="category"Actualiza, pero añade antes dtype={"id": "str"}
Depende de FLAML, darts o similaresActualiza cuando publiquen sus correcciones para 3.1 (yfinance ya lo hizo, en 1.8.0), o filtra Pandas4Warning mientras tanto
Todavía en pandas 2.xHaz primero la migración 2 → 3 (Copy-on-Write, dtype de cadena); 3.1 es pequeño encima de eso
Todavía en NumPy 1.xBloqueado. Actualiza NumPy primero

Usar pandas 3.1 en Jupyter

En el notebook en sí no cambia nada. Dos notas:

  • -W error es una opción de línea de comandos y no se aplica a un kernel en ejecución. Pon warnings.simplefilter("error", pd.errors.Pandas4Warning) en la primera celda mientras limpias el código, y quítalo después.
  • El lector CSV paralelo no necesita la build free-threaded de Python; funciona en el intérprete estándar.

Cuando un archivo grande carga en una fracción de segundo, la parte lenta pasa a ser mirarlo. PyGWalker (opens in a new tab) 0.5.0.1 funcionó con pandas 3.1 en nuestra prueba (pyg.to_html(df) renderizó un DataFrame de 50 000 filas en 0,23 s), así que una pasada de arrastrar y soltar sobre el DataFrame recién cargado es un siguiente paso razonable antes de escribir el código de groupby.

Solución de problemas

ResolutionImpossible / "requires numpy>=2.3.3" — estás en Python 3.14 o 3.15 con un pin antiguo de NumPy. Actualiza NumPy o relaja el pin. En Python 3.11–3.13 el mínimo es 2.0.2.

Cientos de líneas Pandas4Warning desde site-packages — es una dependencia, no tu código. Actualízala; si aún no hay corrección, warnings.filterwarnings("ignore", category=pd.errors.Pandas4Warning) y abre un issue con el traceback.

read_csv no es más rápido — revisa la lista del paso 4. Los culpables habituales son usecols, index_col, un archivo comprimido o un objeto de archivo en lugar de una ruta. Confirma también que pd.get_option("mode.max_threads") no es 1 (por defecto es None, que significa "auto").

df.filter([...]) no devolvió columnas — pasaste una lista de booleanos de forma posicional. Usa df.filter(cond=[...]).

AttributeError: 'Series' object has no attribute 'alias' — las expresiones pd.col no tienen un alias que funcione; nombra la columna con la forma de palabra clave de select.

Los códigos postales perdieron los ceros iniciales — dtype="category" ahora infiere enteros. Lee primero como str.

El dtype de Timedelta cambió de [s] a [us] — es lo esperado en 3.1. Usa .as_unit("s") si un sistema posterior necesita segundos.

Preguntas frecuentes

¿Qué es Pandas4Warning y cómo lo corrijo?

Es el aviso de deprecación que pandas 3.1 lanza por el comportamiento que cambia en 4.0, casi siempre por inplace=True en drop, rename, reset_index, set_index, sort_values, dropna y drop_duplicates. Reasigna el resultado en su lugar: df = df.drop(columns=["a"]). Ejecuta python -W "error:The inplace keyword:DeprecationWarning" your_script.py (o pytest -W error::pandas.errors.Pandas4Warning para una suite de tests) para que se detenga con un traceback en la primera llamada que quede; corrígela y vuelve a ejecutar.

¿Se ha eliminado inplace=True en pandas 3.1?

No. Sigue funcionando en 3.1 e imprime un aviso. La eliminación está prevista para pandas 4.0, y solo en los métodos que nunca modificaron los datos en el sitio. fillna, replace, where, mask, clip e interpolate conservan la palabra clave.

¿Por qué read_csv es más rápido, y por qué el mío no?

El motor C es 2–3x más rápido y los archivos locales grandes se leen en paralelo por defecto. Si no notas ningún cambio, probablemente estés pasando usecols, index_col, nrows, chunksize, un archivo comprimido o un objeto de archivo abierto. Consulta la tabla del paso 4.

¿df.select() es lo mismo que el select de Polars?

La sintaxis es parecida a propósito, pero pandas evalúa de forma inmediata y no tiene optimizador de consultas. Úsalo para cadenas legibles, no por rendimiento.

¿Funciona pandas 3.1 con Python 3.15?

Sí. Se publican wheels para CPython 3.11 a 3.15. En 3.14 y 3.15 necesitas NumPy 2.3.3 o posterior. Para la parte de Python de esa actualización, consulta nuestra guía para actualizar a Python 3.15.

Guías relacionadas