PyArrow 功能#

pandas 可以利用 PyArrow 来扩展功能并提高各种 API 的性能。 这包括

  • 与 NumPy 相比,更广泛的 数据类型

  • 所有数据类型的缺失数据支持 (NA)

  • 高性能 I/O 读取器集成

  • 促进与基于 Apache Arrow 规范的其他数据帧库的互操作性(例如 polars、cuDF)

要使用此功能,请确保您已 安装了最低支持的 PyArrow 版本。

数据结构集成#

一个 SeriesIndexDataFrame 的列可以直接由 pyarrow.ChunkedArray 支持,它类似于 NumPy 数组。要从主要的 pandas 数据结构中构建这些结构,您可以传入类型字符串,后跟 [pyarrow],例如 "int64[pyarrow]""dtype 参数中。

In [1]: ser = pd.Series([-1.5, 0.2, None], dtype="float32[pyarrow]")

In [2]: ser
Out[2]: 
0    -1.5
1     0.2
2    <NA>
dtype: float[pyarrow]

In [3]: idx = pd.Index([True, None], dtype="bool[pyarrow]")

In [4]: idx
Out[4]: Index([True, <NA>], dtype='bool[pyarrow]')

In [5]: df = pd.DataFrame([[1, 2], [3, 4]], dtype="uint64[pyarrow]")

In [6]: df
Out[6]: 
   0  1
0  1  2
1  3  4

注意

字符串别名 "string[pyarrow]" 映射到 pd.StringDtype("pyarrow"),它与指定 dtype=pd.ArrowDtype(pa.string()) 不等效。通常,对数据的操作行为类似,除了 pd.StringDtype("pyarrow") 可以返回 NumPy 支持的可空类型,而 pd.ArrowDtype(pa.string()) 将返回 ArrowDtype

In [7]: import pyarrow as pa

In [8]: data = list("abc")

In [9]: ser_sd = pd.Series(data, dtype="string[pyarrow]")

In [10]: ser_ad = pd.Series(data, dtype=pd.ArrowDtype(pa.string()))

In [11]: ser_ad.dtype == ser_sd.dtype
Out[11]: False

In [12]: ser_sd.str.contains("a")
Out[12]: 
0     True
1    False
2    False
dtype: boolean

In [13]: ser_ad.str.contains("a")
Out[13]: 
0     True
1    False
2    False
dtype: bool[pyarrow]

对于接受参数的 PyArrow 类型,您可以将带有这些参数的 PyArrow 类型传入 ArrowDtype 以在 dtype 参数中使用。

In [14]: import pyarrow as pa

In [15]: list_str_type = pa.list_(pa.string())

In [16]: ser = pd.Series([["hello"], ["there"]], dtype=pd.ArrowDtype(list_str_type))

In [17]: ser
Out[17]: 
0    ['hello']
1    ['there']
dtype: list<item: string>[pyarrow]
In [18]: from datetime import time

In [19]: idx = pd.Index([time(12, 30), None], dtype=pd.ArrowDtype(pa.time64("us")))

In [20]: idx
Out[20]: Index([12:30:00, <NA>], dtype='time64[us][pyarrow]')
In [21]: from decimal import Decimal

In [22]: decimal_type = pd.ArrowDtype(pa.decimal128(3, scale=2))

In [23]: data = [[Decimal("3.19"), None], [None, Decimal("-1.23")]]

In [24]: df = pd.DataFrame(data, dtype=decimal_type)

In [25]: df
Out[25]: 
      0      1
0  3.19   <NA>
1  <NA>  -1.23

如果您已经拥有一个 pyarrow.Arraypyarrow.ChunkedArray,您可以将其传递给 arrays.ArrowExtensionArray 来构建关联的 SeriesIndexDataFrame 对象。

In [26]: pa_array = pa.array(
   ....:     [{"1": "2"}, {"10": "20"}, None],
   ....:     type=pa.map_(pa.string(), pa.string()),
   ....: )
   ....: 

In [27]: ser = pd.Series(pd.arrays.ArrowExtensionArray(pa_array))

In [28]: ser
Out[28]: 
0      [('1', '2')]
1    [('10', '20')]
2              <NA>
dtype: map<string, string>[pyarrow]

要从 SeriesIndex 中检索 pyarrow pyarrow.ChunkedArray,您可以在 SeriesIndex 上调用 pyarrow 数组构造函数。

In [29]: ser = pd.Series([1, 2, None], dtype="uint8[pyarrow]")

In [30]: pa.array(ser)
Out[30]: 
<pyarrow.lib.UInt8Array object at 0x7fac4d182ec0>
[
  1,
  2,
  null
]

In [31]: idx = pd.Index(ser)

In [32]: pa.array(idx)
Out[32]: 
<pyarrow.lib.UInt8Array object at 0x7fac4d593b80>
[
  1,
  2,
  null
]

要将 pyarrow.Table 转换为 DataFrame,您可以使用 types_mapper=pd.ArrowDtype 调用 pyarrow.Table.to_pandas() 方法。

In [33]: table = pa.table([pa.array([1, 2, 3], type=pa.int64())], names=["a"])

In [34]: df = table.to_pandas(types_mapper=pd.ArrowDtype)

In [35]: df
Out[35]: 
   a
0  1
1  2
2  3

In [36]: df.dtypes
Out[36]: 
a    int64[pyarrow]
dtype: object

操作#

PyArrow 数据结构集成是通过 pandas 的 ExtensionArray 接口 实现的;因此,支持的功能存在于该接口集成在 pandas API 中的地方。此外,此功能在可用时使用 PyArrow 计算函数 加速。这包括

  • 数值聚合

  • 数值算术运算

  • 数值舍入

  • 逻辑和比较函数

  • 字符串功能

  • 日期时间功能

以下只是由原生 PyArrow 计算函数加速的操作的一些示例。

In [37]: import pyarrow as pa

In [38]: ser = pd.Series([-1.545, 0.211, None], dtype="float32[pyarrow]")

In [39]: ser.mean()
Out[39]: -0.6669999808073044

In [40]: ser + ser
Out[40]: 
0    -3.09
1    0.422
2     <NA>
dtype: float[pyarrow]

In [41]: ser > (ser + 1)
Out[41]: 
0    False
1    False
2     <NA>
dtype: bool[pyarrow]

In [42]: ser.dropna()
Out[42]: 
0   -1.545
1    0.211
dtype: float[pyarrow]

In [43]: ser.isna()
Out[43]: 
0    False
1    False
2     True
dtype: bool

In [44]: ser.fillna(0)
Out[44]: 
0   -1.545
1    0.211
2      0.0
dtype: float[pyarrow]
In [45]: ser_str = pd.Series(["a", "b", None], dtype=pd.ArrowDtype(pa.string()))

In [46]: ser_str.str.startswith("a")
Out[46]: 
0     True
1    False
2     <NA>
dtype: bool[pyarrow]
In [47]: from datetime import datetime

In [48]: pa_type = pd.ArrowDtype(pa.timestamp("ns"))

In [49]: ser_dt = pd.Series([datetime(2022, 1, 1), None], dtype=pa_type)

In [50]: ser_dt.dt.strftime("%Y-%m")
Out[50]: 
0    2022-01
1       <NA>
dtype: string[pyarrow]

I/O 读取#

PyArrow 还提供已集成到多个 pandas I/O 读取器中的 I/O 读取功能。以下函数提供一个 engine 关键字,该关键字可以调度到 PyArrow 以加速从 I/O 源读取。

In [51]: import io

In [52]: data = io.StringIO("""a,b,c
   ....:    1,2.5,True
   ....:    3,4.5,False
   ....: """)
   ....: 

In [53]: df = pd.read_csv(data, engine="pyarrow")

In [54]: df
Out[54]: 
   a    b      c
0  1  2.5   True
1  3  4.5  False

默认情况下,这些函数以及所有其他 I/O 读取器函数返回 NumPy 支持的数据。这些读取器可以通过指定参数 dtype_backend="pyarrow" 返回 PyArrow 支持的数据。读取器不需要设置 engine="pyarrow" 来返回 PyArrow 支持的数据。

In [55]: import io

In [56]: data = io.StringIO("""a,b,c,d,e,f,g,h,i
   ....:     1,2.5,True,a,,,,,
   ....:     3,4.5,False,b,6,7.5,True,a,
   ....: """)
   ....: 

In [57]: df_pyarrow = pd.read_csv(data, dtype_backend="pyarrow")

In [58]: df_pyarrow.dtypes
Out[58]: 
a     int64[pyarrow]
b    double[pyarrow]
c      bool[pyarrow]
d    string[pyarrow]
e     int64[pyarrow]
f    double[pyarrow]
g      bool[pyarrow]
h    string[pyarrow]
i      null[pyarrow]
dtype: object

几个非 I/O 读取器函数也可以使用 dtype_backend 参数返回 PyArrow 支持的数据,包括