Nine months after the big 3.0 release, pandas 3.1 arrived on 22 October 2026. It is a smaller release, but three changes affect almost everyone who uses pandas: a new DataFrame.select method, boolean conditions in filter, and a CSV reader that is much faster and now reads large files in parallel. It also starts the removal of the inplace argument. We installed it and tested every example on this page. If you are still on pandas 2, read our pandas 3 upgrade guide first.
DataFrame.select: choose and create columns in one step
Until now, picking columns used df[["a", "b"]] and creating columns used assign. The new select does both, and works with pd.col, the expression helper added in pandas 3.0. Later columns can use ones created earlier in the same call.
import pandas as pd
df = pd.DataFrame({
"first_name": ["John", "Alice", "Bob"],
"last_name": ["Smith", "Cooper", "Marley"],
"age": [61, 22, 35],
})
df.select(
"first_name",
age_months=pd.col("age") * 12,
age_days=pd.col("age_months") * 30,
)
# first_name age_months age_days
# 0 John 732 21960
# 1 Alice 264 7920
# 2 Bob 420 12600filter with conditions
DataFrame.filter used to select columns or rows by label only. It now takes a cond argument: a boolean mask, a function, or a pd.col expression. Missing values in the mask count as False unless you say otherwise.
df.filter(pd.col("age") > 30) # expression
df.filter(cond=df["age"] > 30) # boolean mask
df.filter(lambda d: d["age"] < 40) # function
mask = pd.array([True, None, False], dtype="boolean")
df.filter(cond=mask) # missing value treated as False: 1 row
df.filter(cond=mask, na=True) # missing value kept: 2 rowsOne change to watch: passing a plain list of True and False values to filter now gives a warning. Use items= to select labels, or cond= for a mask.
A much faster read_csv
The default C engine was rewritten for speed, and large, uncompressed local files of 5 MB or more are now read in parallel. The result is identical to a single-threaded read. We timed a 90 MB file with 2 million rows on a small 2-core cloud machine, best of five runs:
Our test: 2 million rows, 5 columns, 2-core cloud machine, best of five runs. Your numbers will vary with hardware and file shape.
Even on one thread, 3.1 was 3.6 times faster than 3.0, and with parallel reading it matched Polars on this file. The new mode.max_threads option limits the threads, which is useful on shared servers:
with pd.option_context("mode.max_threads", 1):
df = pd.read_csv("large.csv")Goodbye, inplace
The inplace argument is deprecated on methods that never really worked in place, including drop, rename, reset_index, set_index, dropna, sort_values, query and eval. In our test, pandas warned even when inplace=False was passed, so remove the argument entirely. fillna and replace keep it.
# Before
df.drop(columns="age", inplace=True)
# After
df = df.drop(columns="age")Breaking changes to check
- Numeric dates
- to_datetime, to_timedelta, Timestamp and Timedelta now default to microseconds for numbers, so pd.to_timedelta([1, 2], unit="s") gives timedelta64[us]. Use .as_unit() if you need nanoseconds.
- Read-only index values
- Index.values and Index.array are now read-only for every dtype.
- total_seconds
- Timedelta.total_seconds() now includes nanoseconds, so tiny durations are no longer 0.0.
- Category columns from CSV
- read_csv(dtype="category") now infers numbers and booleans. Read as "str" first if you need text categories.
- select_dtypes
- Passing Python classes such as decimal.Decimal now raises; pass object instead.
- HDF5 files
- Tables written by pandas 3.1 cannot be read by pandas 3.0 or earlier.
- numexpr
- Version 2.14.1 is ignored; install 2.14.2 or newer to keep the speed-up.
Smaller additions worth knowing
pd.concatgainsunion_categories=Trueto combine categorical columns with different categories.- Periods format in f-strings:
f"{period:%Y-%m}"gives2026-10. Timestamp.round,floorandceilaccept aTimedelta.- Time strings with a space before AM or PM, such as
"3:25:00 PM", now parse. Index.replaceworks likeSeries.replace.
How to upgrade
- 1
Upgrade in a test environment
pandas 3.1 needs Python 3.11 or newer and NumPy 2.0.2 or newer. Run pip install -U pandas, or uv add pandas, in a separate environment first.
- 2
Turn warnings on
Run your tests with deprecation warnings as errors, for example pytest -W error::DeprecationWarning, to find inplace calls and other deprecated code. pandas uses its own Pandas4Warning, a kind of DeprecationWarning.
- 3
Check dates and categories
Look for code that depends on nanosecond resolution or on text categories from read_csv.
- 4
Remove inplace
Replace each inplace=True with an assignment; it also makes method chains easier to read.
- 5
Try select and filter
New code reads more clearly with them, but old code keeps working.
Check your understanding
1/3What does the new DataFrame.select method do?
Use filter for rows; select is for columns, including computed ones.
2/3How are missing values in a boolean mask treated by filter by default?
Pass na=True to keep them, or na="raise" to raise an error.
3/3What should you do with inplace=True on drop or rename?
Even inplace=False triggers the warning, so remove the argument.
You got 0 out of 3.
More on Python data tools: the pandas 3 upgrade guide, what's new in Polars 2.1, pandas vs Polars in 2026 and the pandas cheat sheet.
Sources: pandas 3.1.0 release notes, "What's new in 3.1.0" (22 October 2026), and our own tests with pandas 3.0.6 and 3.1.0, Polars 2.1.0 and PyArrow on Python 3.13. Timings are from one machine and are indicative only.
