跳转至

Pandas 2 新特性

为什么要学 Pandas 2 新特性

Pandas 2.0 是一次重大升级,引入了 Apache Arrow 后端、改进的数据类型系统和显著的性能提升。Arrow 后端让 Pandas 在处理大数据集时内存占用降低 50-90%,字符串操作速度提升数倍。对于每天使用 Pandas 进行数据分析的用户来说,了解这些新特性可以直接提升工作效率。


核心概念

概念白话解释用途
Arrow BackendApache Arrow 后端替代 NumPy 的列式内存格式
ArrowDtypeArrow 数据类型更丰富的类型支持
Copy-on-Write (CoW)写时复制避免意外修改原始数据
Nullable Types可空类型整数/布尔列可包含 NA
PyArrow stringsArrow 字符串更高效的字符串处理

安装配置

pip install "pandas>=2.0" pyarrow

快速上手

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