Pandas 2 新特性¶
为什么要学 Pandas 2 新特性¶
Pandas 2.0 是一次重大升级,引入了 Apache Arrow 后端、改进的数据类型系统和显著的性能提升。Arrow 后端让 Pandas 在处理大数据集时内存占用降低 50-90%,字符串操作速度提升数倍。对于每天使用 Pandas 进行数据分析的用户来说,了解这些新特性可以直接提升工作效率。
核心概念¶
| 概念 | 白话解释 | 用途 |
|---|---|---|
| Arrow Backend | Apache Arrow 后端 | 替代 NumPy 的列式内存格式 |
| ArrowDtype | Arrow 数据类型 | 更丰富的类型支持 |
| Copy-on-Write (CoW) | 写时复制 | 避免意外修改原始数据 |
| Nullable Types | 可空类型 | 整数/布尔列可包含 NA |
| PyArrow strings | Arrow 字符串 | 更高效的字符串处理 |
安装配置¶
快速上手¶
Arrow 后端¶
import pandas as pd
# 使用 Arrow 后端读取数据
df = pd.read_csv("data.csv", dtype_backend="pyarrow")
df = pd.read_parquet("data.parquet", dtype_backend="pyarrow")
# 查看数据类型
print(df.dtypes)
# name string[pyarrow]
# age int64[pyarrow]
# score double[pyarrow]
# 全局设置 Arrow 后端
pd.set_option("mode.dtype_backend", "pyarrow")
# 内存对比
df_numpy = pd.read_csv("large.csv")
df_arrow = pd.read_csv("large.csv", dtype_backend="pyarrow")
print(f"NumPy: {df_numpy.memory_usage(deep=True).sum() / 1e6:.1f} MB")
print(f"Arrow: {df_arrow.memory_usage(deep=True).sum() / 1e6:.1f} MB")
可空整数类型¶
# 旧版:整数列有 NaN 会变成 float64
# Pandas 2:支持 Nullable Integer
s = pd.array([1, 2, None, 4], dtype="Int64") # 注意大写 I
print(s) # [1, 2, <NA>, 4]
print(s.dtype) # Int64
# Arrow 版本
s = pd.array([1, 2, None, 4], dtype="int64[pyarrow]")
Copy-on-Write¶
# 启用 CoW(Pandas 3.0 将默认启用)
pd.set_option("mode.copy_on_write", True)
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
df2 = df[["a"]] # 不再是视图,修改 df2 不会影响 df
df2.iloc[0] = 100
print(df) # 原始数据不变
进阶用法¶
性能对比¶
import pandas as pd
import time
# 字符串操作性能对比
n = 1_000_000
df_old = pd.DataFrame({"text": ["hello world"] * n})
df_arrow = pd.DataFrame({"text": pd.array(["hello world"] * n, dtype="string[pyarrow]")})
start = time.time()
df_old["text"].str.upper()
print(f"Object dtype: {time.time()-start:.3f}s")
start = time.time()
df_arrow["text"].str.upper()
print(f"Arrow dtype: {time.time()-start:.3f}s")
# Arrow 通常快 3-10 倍
新的 GroupBy 功能¶
# named aggregation(命名聚合)
result = df.groupby("category").agg(
avg_price=("price", "mean"),
total_qty=("quantity", "sum"),
unique_products=("product", "nunique"),
)
Parquet 优化¶
# 读取特定列(列式存储优势)
df = pd.read_parquet("data.parquet", columns=["name", "age"])
# 过滤读取
df = pd.read_parquet("data.parquet",
filters=[("age", ">", 25), ("city", "==", "Beijing")])
# 写入压缩
df.to_parquet("output.parquet", compression="zstd", index=False)
类型转换最佳实践¶
# 自动选择最佳类型
df = df.convert_dtypes()
# 降低内存
df = df.astype({
"id": "int32[pyarrow]",
"name": "string[pyarrow]",
"score": "float32[pyarrow]",
"is_active": "bool[pyarrow]",
})
常见问题¶
Q: Arrow 后端兼容性如何?¶
大部分 Pandas 操作都兼容。少数边界情况可能有差异,建议逐步迁移并测试。
Q: 什么时候用 Arrow 后端?¶
- 数据集较大(>100MB)
- 大量字符串操作
- 需要与 Arrow/Parquet 生态交互
- 需要可空整数/布尔类型
Q: CoW 会影响现有代码吗?¶
如果代码依赖"切片是视图"的行为,启用 CoW 后可能产生不同结果。建议先运行测试。
参考资源¶
- Pandas 2.0 更新日志:https://pandas.pydata.org/docs/whatsnew/v2.0.0.html
- Arrow 后端文档:https://pandas.pydata.org/docs/user_guide/pyarrow.html
- CoW 文档:https://pandas.pydata.org/docs/user_guide/copy_on_write.html
- 迁移指南:https://pandas.pydata.org/docs/dev/whatsnew/v2.0.0.html#migration-guide