pandas 3.1 升级指南:解决 inplace 弃用的 Pandas4Warning、用 df.select() 和 pd.col()、read_csv 并行加速实测
更新于

先说结论: pandas 3.1.0 已于 2026 年 10 月 22 日发布,11 月 4 日又发布了 3.1.1 修复版。直接升到 3.1.1:
pip install --upgrade "pandas>=3.1"
# or, in a uv project
uv add "pandas>=3.1"升级之后会发生三件事:
- 代码会打印
Pandas4Warning警告:drop、rename、reset_index、set_index、sort_values、dropna、drop_duplicates等方法上的每一个inplace=True都会触发。修法很机械:把df.drop(..., inplace=True)改成df = df.drop(...)。警告经常来自你用的某个库,而不是你自己的代码。 pd.read_csv读取大的本地文件快了很多。 我们测试的一个 72 MB 文件,在 pandas 3.0.1 上要 0.23 s,在 3.1 上只要 0.02 s。有几个常用参数会把这个加速关掉,下文会列出。- 多了一套 Polars 风格的 API:
df.select("a", pd.col("b") * 2)和df.filter(pd.col("a") > 1)。
如果你还在 pandas 2.x,升到 3.x(Copy-on-Write、默认字符串 dtype)才是更大的变化,应该从 pandas 3.0 迁移指南 (opens in a new tab) 开始。本文只讲 3.0 → 3.1,以及我们踩到的坑。
测试说明: 下文标注"实测"的内容,均于 2026 年 11 月 1 日在 Apple M4 Max(16 核,macOS)上完成,环境是新建的
uv虚拟环境,CPython 3.14.2、pandas 3.1.0、NumPy 2.5.4、PyArrow 26.0.0。对比数据来自同一台机器上的 pandas 3.0.1 + NumPy 2.4.2,未安装 PyArrow。Windows、Linux、conda 和 Docker 上的行为来自官方文档,没有实测。2026 年 11 月 4 日,所有实测内容都在 pandas 3.1.1 上重跑了一遍,结果相同。
3.1 里你会实际碰到的变化
| 变化 | 对你的影响 | 怎么做 |
|---|---|---|
11 个方法的 inplace 被弃用(PDEP-8) | 每次调用都会发出 Pandas4Warning;pandas 4.0 将移除 | 重新赋值:df = df.drop(...) |
read_csv 并行读取,针对本地未压缩、≥ 5 MB 的文件 | 单线程快 2–3 倍,再加上默认最多 6 个线程 | 不用做什么,除非你传了 usecols、index_col、nrows 或文件句柄(见下文) |
新增 DataFrame.select()(接受 pd.col() 表达式,后者 3.0 起就有) | 一次调用完成选列和计算列,Polars 风格 | 可选;在方法链里很好用 |
filter(cond=...) 接受布尔掩码 | df.filter(pd.col("a") > 1) 按行筛选 | 注意:按位置传入的布尔列表仍然按标签选择 |
| 要求 NumPy ≥ 2.0.2(Python 3.14 上 ≥ 2.3.3) | NumPy 1.x 环境装不上 3.1 | 先升级 NumPy,或固定 pandas<3.1 |
| 数值输入默认按微秒解析 | pd.to_timedelta([1], unit="s") 现在是 timedelta64[us],不是 [s] | 修复了 3.0 的一个取整 bug;需要特定精度时用 .as_unit() |
read_csv 的 dtype="category" 会推断数值类别 | 邮编和 ID 会丢掉前导零 | 先按 str 读这些列 |
完整列表见 官方 What's new in 3.1.0 (opens in a new tab)。本文后面按顺序讲要动手做的事:安装、修警告、用新 API、加速 CSV 读取,以及检查那些不报错但会改变结果的行为变化。
- pandas 3.1 升级指南:inplace 弃用警告、df.select() 与 read_csv 并行加速
- OpenCode 2.0 升级教程:从 1.x 迁移配置、插件与会话(附回滚方法)
- Python 3.15 安装与升级指南:用 uv 安装、延迟导入提速、数据科学库兼容性实测
- Claude Code Mods 教程:从零写出第一个 Mod、测试与安装,附 15 个社区案例
- Pi Coding Agent 1.0 使用教程:安装、接入模型(含 Ollama 本地模型)并跑通第一个任务
- Claude Code 现在会读 AGENTS.md:配置方法、四种加载模式,以及如何与 Codex、OpenCode、Cursor 共用一份文件
- GPT Image 2.5 使用指南:Flare 与 Sunburst 怎么选、API 调用与价格
- DeepSeek Harness 安装教程:一条命令装好 DSH 并跑通第一个任务
- Runcell Science:面向科研的开源 Claude Science 替代方案
- Mac 怎么不休眠:合盖继续运行 Codex、Claude Code 和本地 AI Agent
- OpenClaw vs ZeroClaw vs Pi Agent vs Nanobot:2026 年该选哪个 AI Agent 技术栈?
- Claude Code 能分析 Jupyter Notebook 吗?Data Science 场景下它到底做了什么
- Claude Code Routines 是什么?AI Agent 定时任务与自动触发指南
- Claude Code Desktop 绕过权限:如何开启 Bypass permissions
- 如何用 Google 的 A2A 协议构建两个 Python Agent:一步步教程
- 2025 年 Python 增长最快的 10 个数据可视化库
第 1 步:安装 pandas 3.1
版本要求(实测)
pandas 3.1.0 为 CPython 3.11 到 3.15 提供 wheel(requires_python >= 3.11),PyPI 和 conda-forge 上都有。NumPy 的最低版本取决于你的 Python 版本:
| Python | NumPy 最低版本 |
|---|---|
| 3.11 – 3.13 | 2.0.2 |
| 3.14 – 3.15 | 2.3.3 |
whatsnew 页面只提到 2.0.2。在 Python 3.14 上,wheel 元数据要求 2.3.3,解析器按这个执行。固定 NumPy 1.x 会直接失败:
× 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.如果某个依赖仍然固定 numpy<2,挡住升级的是那个依赖,不是 pandas。要么更新它,要么在它更新之前继续用 pandas<3.1。
升级(uv 实测)
请装 3.1.1,不要装 3.1.0:3.1.1 修复了一个回归问题,read_csv 和 to_csv 会把 pytest 的 tmpdir 这类路径对象当成已打开的文件句柄,可能报错或写出不完整的文件(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 上已经有 3.1.1(2026 年 11 月 4 日确认;conda install -c conda-forge "pandas>=3.1"),未实测。
如果还没装 PyArrow,顺手装上。pandas 3 在有 PyArrow 时会用它实现默认的字符串 dtype,engine="pyarrow" 的 CSV 读取器也需要它。
第 2 步:解决 inplace 的 Pandas4Warning
升级后,像这样的代码:
df.drop(columns=["rain"], inplace=True)会打印:
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.哪些方法受影响(实测)
这次弃用覆盖的是那些 inplace=True 从来没有真正原地修改过值的方法。对 dropna、sort_values 以及其他会重排行的方法来说,它底层一直是重新赋值;而 drop、rename 或 set_index 过去能省下的那次拷贝,在 pandas 3.0 引入 Copy-on-Write 之后本来也不会再发生。
| 方法 | 3.1 中的 inplace | 修法 |
|---|---|---|
drop、rename、rename_axis | 已弃用 | df = df.drop(...) |
reset_index、set_index | 已弃用 | df = df.reset_index() |
sort_values、sort_index | 已弃用 | df = df.sort_values("col") |
dropna、drop_duplicates | 已弃用 | df = df.dropna() |
eval、query | 已弃用 | df = df.query("a > 1") |
fillna、replace、where、mask、clip、interpolate | 保留(它们可以原地更新值) | 不用改 |
在我们的测试中,全部 11 个被弃用的方法在传 inplace=True 时都发出了警告;fillna 和 replace 没有,与文档一致。
替换是每处调用改一行:
# 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)
)找出代码库里的每一处调用(实测)
把警告临时变成错误跑一次,traceback 会直接指到那一行。python -W 不接受 pandas.errors.Pandas4Warning 这样的第三方类:它会打印 Invalid -W option ignored: invalid module name: 'pandas.errors',然后照常运行脚本。改为按消息文本匹配:
python -W "error:The inplace keyword:DeprecationWarning" your_script.py如果想把所有 Pandas4Warning 都变成错误,而不只是 inplace 相关的:
python -c "import runpy, warnings, pandas as pd; warnings.simplefilter('error', pd.errors.Pandas4Warning); runpy.run_path('your_script.py', run_name='__main__')"两种写法都会在第一处 inplace 调用处带着 traceback 退出。按消息过滤不会影响其他无关的弃用警告。
测试套件的情况不同:pytest 在 pandas 可以导入之后才应用 -W 过滤器,所以在那里可以直接写类名:
pytest -W error::pandas.errors.Pandas4WarningPandas4Warning 是 PandasDeprecationWarning 的子类,按任意一个过滤都可以。grep 也能找出大部分:
grep -rn "inplace=True" --include="*.py" --include="*.ipynb" .警告来自某个库,而不是你的代码
这是新版本发布后前几周最常见的情况。2026 年 10 月 22 日到 11 月 1 日之间,GitHub 上新增了约 300 个提到 Pandas4Warning 的 issue 和 PR,以及约 3,500 个提到 "pandas 3.1" 的,涉及 yfinance(8 个文件里 29 处 inplace 调用,yfinance #3009 (opens in a new tab);已在 11 月 3 日发布的 yfinance 1.8.0 中修复)、FLAML、marimo、cuDF、darts 和 category_encoders 等项目。
这些你没法从自己的代码里修。可选方案,按优先顺序:
- 更新这个库。 很多库几天内就发布了修复。
- 只屏蔽这一类警告,等库跟上来,而不是屏蔽所有警告:
import warnings
import pandas as pd
warnings.filterwarnings("ignore", category=pd.errors.Pandas4Warning)- 把
pandas<3.1固定下来,只在运行那个无人维护的库的环境里这么做。不要永远固定在 pandas 3.0;inplace关键字会在 4.0 移除,这个警告就是给你的过渡期。
3.1 里你可能碰到的其他弃用(除标注外均为实测)
| 现在会警告的写法 | 替代写法 |
|---|---|
s.dt.dayofweek、.dayofyear、.daysinmonth | s.dt.day_of_week、.day_of_year、.days_in_month |
对字符串列用 df.select_dtypes(include="object")(3.0 已经会警告;3.1 新增了 exclude="object") | 显式传 "str";在 pandas 3 里 "object" 不再表示"文本" |
对 float 列用 s.fillna("missing") | 先转成共同的 dtype;未来版本会直接报错 |
对带时区的列用 ser.values | ser.array、ser.to_numpy(),或用 ser.dt.tz_convert(None).to_numpy() 保留旧的 UTC 数组 |
pd.infer_freq(idx) 返回 "D" | 将改为返回 offset 对象;用 .freqstr,或设置 future.infer_freq_returns_offset |
read_parquet(engine="fastparquet")(文档) | fastparquet 已退役;用默认的 PyArrow 引擎 |
pd.set_eng_float_format()(文档) | pd.set_option("display.precision", n) |
第 3 步:使用 df.select()、pd.col() 和 filter(cond=)
DataFrame.select() 和 filter(cond=) 是 3.1 里肉眼可见的新 API。pd.col() 本身在 pandas 3.0 就已出现,用于 assign() 和 .loc;到了 3.1,它自然成了这两个新方法的参数。用过 Polars 的话会觉得很熟悉。
select 一次调用完成选列和计算列(实测)
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后面的参数可以引用同一次调用里前面刚创建的列,和 assign 一样:
df.select(temp_c=pd.col("temp"), temp_f=pd.col("temp_c") * 1.8 + 32)pd.col("temp") 是一个 pandas.api.typing.Expression。它支持你在 Series 上会用的运算符和访问器,包括 .str 和 .round():
df.select(pd.col("city").str.upper(), pd.col("temp").round(0))三个让我们绊了一下的地方(实测):
- 没有
.alias()。 计算列要用关键字形式命名(temp_f=...)。pd.col("temp").alias("x")本身构建时不会报错,但随后df.select(...)会失败,报AttributeError: 'Series' object has no attribute 'alias'。 - 归约成标量的表达式,比如
pd.col("temp").mean(),必须以关键字传入(mean_temp=pd.col("temp").mean()),结果会广播到每一行。按位置传入会抛TypeError。 - 列不存在时抛
KeyError,和df[["nope"]]一样。
filter(cond=) 用布尔掩码筛选行(实测)
DataFrame.filter 过去只能选标签(items=、like=、regex=)。3.1 开始它也接受掩码:
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链式写法读起来像 Polars,但仍然是 pandas DataFrame:
(
df.filter(pd.col("rain") < 20)
.select("city", "temp")
.sort_values("temp")
)掩码里的缺失值默认按 False 处理;传 na=True 保留它们,或传 na="raise" 直接报错。
坑在这里: 按位置传入的普通布尔列表仍然走标签路径。在我们的测试中,df.filter([True, False, True]) 返回了一个零列的 DataFrame,并附带一条让我们改用 cond= 的 UserWarning。掩码是列表或数组时,一定要写 cond=。
Polars 与 pandas 3.1 对照
| 任务 | Polars | pandas 3.1 |
|---|---|---|
| 选列 | df.select("a", "b") | df.select("a", "b") |
| 计算列 | df.select(pl.col("a") * 2) | df.select(pd.col("a") * 2) |
| 命名 | (pl.col("a") * 2).alias("a2") | df.select(a2=pd.col("a") * 2) |
| 筛选行 | df.filter(pl.col("a") > 1) | df.filter(pd.col("a") > 1) |
| 聚合 | df.select(pl.col("a").mean()) → 1 行 | df.select(m=pd.col("a").mean()) → 广播到每一行 |
pandas 并没有变成 Polars:select 背后没有惰性求值,也没有查询优化器。它只是让链式写法更易读、不用反复写 DataFrame 名字的语法。如果你在考虑要不要换引擎,Polars 和 pandas 的取舍需要单独比较,本文不展开。
第 4 步:用上更快的 read_csv,并知道什么会把它关掉
基准测试(实测)
一个文件:3,000,000 行 × 3 列(float、int、string),72.5 MB,未压缩,本地 SSD。三次取最优。
| 读取方式 | 耗时 | 相对 pandas 3.0.1 |
|---|---|---|
pandas 3.0.1,engine="c" | 0.233 s | 1x |
pandas 3.1.0,mode.max_threads = 1(串行) | 0.089 s | 2.6x |
| pandas 3.1.0,2 线程 | 0.049 s | 4.8x |
| pandas 3.1.0,4 线程 | 0.025 s | 9.3x |
| pandas 3.1.0,默认(6 线程) | 0.018 s | 13x |
pandas 3.1.0,engine="pyarrow" | 0.030 s | 7.8x |
串行那一行和发布说明一致("快两到三倍");并行的几行是在此基础上再叠加。你的文件会不一样(字符串列越多解析越慢),但结果的形状才是重点:对于普通的本地文件,默认的 engine="c" 读取器现在比 PyArrow 还快。
触发条件(来自文档,上面的计时可以印证)
满足以下全部条件时,并行路径自动启用:
filepath_or_buffer是本地、未压缩的文件路径- 使用默认的 C 引擎
- 数据行总大小至少 5 MB
mode.max_threads大于 1(默认为 CPU 数量,上限 6;进程被限制为单 CPU 时为 1)- 没有需要一次读完整个文件的选项:
iterator、chunksize、nrows、usecols、index_col、parse_dates、列表或可调用对象形式的skiprows、多行表头,或非 UTF-8 编码
其他情况都会回退到串行读取器,结果始终与串行读取完全一致。
我们测试中的实际表现(实测)
| 调用 | 耗时 | 并行? |
|---|---|---|
pd.read_csv("big.csv") | 0.018 s | 是 |
pd.read_csv("big.csv", usecols=["a", "c"]) | 0.079 s | 否 |
pd.read_csv("big.csv", index_col=0) | 0.091 s | 否 |
pd.read_csv("big.csv", nrows=1_000_000) | 0.032 s | 否(串行,只读了文件的三分之一) |
pd.read_csv("big.csv", converters={"b": int}) | 0.255 s | 否(比普通读取慢,但仍比 3.0 上的同一调用快) |
pd.read_csv(open("big.csv", "rb")) | 0.091 s | 否(文件句柄,不是路径) |
pd.read_csv(io.StringIO(text)) | 0.131 s | 否 |
pd.read_csv("big.csv.gz") | 0.163 s | 否(压缩文件) |
pd.concat(pd.read_csv("big.csv", chunksize=500_000)) | 0.099 s | 否 |
pd.read_csv("big.csv", dtype={...}) | 0.034 s | 是(显式 dtype 没问题) |
pd.read_csv("big.csv", na_values=["z"]) | 0.025 s | 是 |
两个实际影响:
usecols现在可能让读取变慢,而不是变快。 多年来的建议是"传usecols跳过不需要的列"。在 3.1 上读 ≥ 5 MB 的本地文件时,我们测试中并行读完所有列再丢掉多余的列,比usecols快 4 倍。先测一下,再决定要不要保留老习惯。- 传路径,不要传句柄。
pd.read_csv("file.csv")是并行的;pd.read_csv(open("file.csv"))不是。那些把打开的文件对象而不是路径交给 pandas 的封装层会失去加速。
在已经并行的应用里把线程数调低
如果 pandas 运行在 Dask、Ray、multiprocessing 进程池,或已经占满所有核心的 Web worker 里,限制一下线程数,避免互相争抢:
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)在 Docker 和 Kubernetes 里,上限跟随 cgroup 的 CPU 配额(来自文档,未实测),所以被限制为单 CPU 的容器会自动串行读取,你不需要做任何事。
第 5 步:检查不报错的行为变化
这些是最可能悄悄改变结果的变化。每一项都在 3.0.1 和 3.1.0 上复现过(实测)。
数值转 Timedelta 和 datetime 现在默认微秒精度
在 3.0 里,pd.to_timedelta([1], unit="s") 生成 timedelta64[s],算术运算保持这个精度。除法会被取整到整秒:
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 的修法是:无论你用什么 unit 转换,默认都用微秒。如果你的代码比较过 dtype,或依赖 [s] 精度,请显式调用 .as_unit("s")。Timestamp 和 to_datetime 接收数值输入时也做了同样的改变。
相关:Timedelta.total_seconds() 现在包含纳秒。pd.Timedelta(nanoseconds=1500).total_seconds() 返回 1.5e-06,而不是 1e-06。
read_csv 的 dtype="category" 会推断数值类别
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 goneC 引擎现在的行为和 PyArrow 引擎之前的行为一致。邮编、账号以及任何补零的标识符,先按 str 读进来再转换:
df = pd.read_csv("file.csv", dtype={"zip": "str"})
df["zip"] = df["zip"].astype("category")以前静默通过、现在会报错的写法
pd.Timestamp(datetime(2020, 12, 31), hour=5)在我们的测试中抛ValueError;3.0 会静默忽略hour。改为全部用关键字传入各个分量。pd.to_timedelta("3:25:00 PM")会报错;3.0 把它解析成三小时,并丢掉了PM。- DataFrame 沿默认的
axis="columns"与category类型的 Series 做算术和大小比较(例如df + cat_series)现在会抛TypeError,而不是对类别值进行运算;相等比较不变(文档,已复现)。 Index.values和Index.array返回只读数组,之前通过它们修改索引的代码现在会明确报错,而不是悄悄破坏查找(文档)。
PyArrow 字符串上的正则(实测)
安装了 PyArrow 时,pandas 3.0 里 .str.replace、.str.count 等方法中的 \w、\d、\s、\b 只匹配 ASCII。3.1 恢复为匹配 Unicode,与 Python 的 re 和 pandas 2.x 一致。在 PyArrow 26.0.1 下,pd.Series(["héllo wörld", "naïve 東京"]).str.count(r"\w") 在 pandas 3.0.6 上返回 [8, 4],在 3.1.1 上返回 [10, 7]。如果你处理非英文文本,升到 3.0 后发现计数变少,这就是修复。3.1.1 还修复了 PyArrow 字符串上 \s 不匹配 \x0b 和 \x1c 的问题。
现在该不该升级?
| 你的情况 | 建议 |
|---|---|
| 新项目,Python 3.11+ | 升。直接从 3.1 开始,不写 inplace |
| 3.0 上的脚本和 notebook | 升。用 -W "error:The inplace keyword:DeprecationWarning"(或 pytest -W error::pandas.errors.Pandas4Warning)跑一次,改掉那几行,用上更快的 CSV 读取 |
用 dtype="category" 加载补零 ID 的库或流水线 | 升,但先加上 dtype={"id": "str"} |
| 依赖 FLAML、darts 之类 | 等它们发布 3.1 修复后再升(yfinance 已在 1.8.0 中修复),或先过滤掉 Pandas4Warning |
| 还在 pandas 2.x | 先做 2 → 3 迁移(Copy-on-Write、字符串 dtype);3.1 在那之上只是小改动 |
| 还在 NumPy 1.x | 被挡住了。先升级 NumPy |
在 Jupyter 里使用 pandas 3.1
notebook 本身没有变化。两点说明:
-W error是命令行参数,对正在运行的内核不起作用。清理期间把warnings.simplefilter("error", pd.errors.Pandas4Warning)放在第一个单元格里,改完再删掉。- 并行 CSV 读取器不需要自由线程版 Python;标准解释器就能用。
大文件零点几秒就能加载之后,慢的环节就变成了看数据。PyGWalker (opens in a new tab) 0.5.0.1 在我们的测试中可以在 pandas 3.1 上运行(pyg.to_html(df) 渲染一个 50,000 行的 DataFrame 用了 0.23 s),所以在动手写 groupby 代码之前,先对刚加载的 DataFrame 拖拽着看一遍,是个合理的下一步。
常见问题排查
ResolutionImpossible / "requires numpy>=2.3.3" — 你在 Python 3.14 或 3.15 上,NumPy 被固定在旧版本。升级 NumPy 或放宽固定。Python 3.11–3.13 上的最低版本是 2.0.2。
site-packages 里冒出几百行 Pandas4Warning — 来自某个依赖,不是你的代码。更新它;如果还没有修复,先 warnings.filterwarnings("ignore", category=pd.errors.Pandas4Warning),并带着 traceback 去提 issue。
read_csv 没有变快 — 对照第 4 步的列表。常见原因是 usecols、index_col、压缩文件,或者传了文件对象而不是路径。另外确认 pd.get_option("mode.max_threads") 不是 1(默认是 None,表示"自动")。
df.filter([...]) 返回了零列 — 你按位置传了布尔列表。改用 df.filter(cond=[...])。
AttributeError: 'Series' object has no attribute 'alias' — pd.col 表达式没有可用的 alias;用 select 的关键字形式给列命名。
邮编丢了前导零 — dtype="category" 现在会推断成整数。先按 str 读。
Timedelta 的 dtype 从 [s] 变成了 [us] — 3.1 的预期行为。下游系统需要秒时用 .as_unit("s")。
常见问题
Pandas4Warning 是什么,怎么解决?
它是 pandas 3.1 针对将在 4.0 改变的行为发出的弃用警告,最常见的触发点是 drop、rename、reset_index、set_index、sort_values、dropna 和 drop_duplicates 上的 inplace=True。改为重新赋值:df = df.drop(columns=["a"])。运行 python -W "error:The inplace keyword:DeprecationWarning" your_script.py(测试套件用 pytest -W error::pandas.errors.Pandas4Warning),会在剩下的第一处调用停下并给出 traceback;改完再运行一次。
pandas 3.1 移除 inplace=True 了吗?
没有。3.1 里它仍然可用,只是会打印警告。移除计划在 pandas 4.0,而且只针对那些从未真正原地修改数据的方法。fillna、replace、where、mask、clip 和 interpolate 保留这个关键字。
read_csv 为什么更快了?我的为什么没变快?
C 引擎快了 2–3 倍,大的本地文件默认并行读取。如果没看到变化,多半是传了 usecols、index_col、nrows、chunksize、压缩文件,或者打开的文件对象。见第 4 步的表格。
df.select() 和 Polars 的 select 一样吗?
语法刻意做得相似,但 pandas 是立即求值,没有查询优化器。用它来写易读的链式调用,不要指望它带来性能提升。
pandas 3.1 支持 Python 3.15 吗?
支持。官方为 CPython 3.11 到 3.15 发布了 wheel。在 3.14 和 3.15 上需要 NumPy 2.3.3 或更高版本。Python 这一侧的升级可以看我们的 Python 3.15 升级指南。
相关指南
- Pandas read_csv() 教程:像专业人士一样导入 CSV 文件
- Pandas 删除列:如何从 DataFrame 中删除列
- Pandas 过滤行:在 Python 中按条件选择数据
- 如何在 Pandas 中重命名列
- Python 3.15 安装与升级指南
- 如何升级 Python 包