PyArrowの機能#
pandasはPyArrowを利用して、様々なAPIの機能を拡張し、パフォーマンスを向上させることができます。これには以下の機能が含まれます。
NumPyと比較してより広範なデータ型
すべてのデータ型における欠損データサポート (NA)
高性能なIOリーダーの統合
Apache Arrow仕様に基づいた他のデータフレームライブラリ (例: polars, cuDF) との相互運用性を促進
この機能を使用するには、サポートされている最低限のPyArrowバージョンがインストールされていることを確認してください。
データ構造の統合#
Series、Index、またはDataFrameの列は、NumPy配列に似たpyarrow.ChunkedArrayによって直接サポートされます。これらのデータ構造を主要なpandasデータ構造から構築するには、dtypeパラメーターに、型の文字列の後に[pyarrow]を付けたもの (例: "int64[pyarrow]"") を渡します。
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をバックエンドとするnull許容型を返す可能性があるのに対し、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.Arrayまたはpyarrow.ChunkedArrayがある場合は、それをarrays.ArrowExtensionArrayに渡して、関連するSeries、Index、またはDataFrameオブジェクトを構築することができます。
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]
SeriesまたはIndexからpyarrowのpyarrow.ChunkedArrayを取得するには、SeriesまたはIndexに対してpyarrow配列コンストラクターを呼び出すことができます。
In [29]: ser = pd.Series([1, 2, None], dtype="uint8[pyarrow]")
In [30]: pa.array(ser)
Out[30]:
<pyarrow.lib.UInt8Array object at 0x7f9434594340>
[
1,
2,
null
]
In [31]: idx = pd.Index(ser)
In [32]: pa.array(idx)
Out[32]:
<pyarrow.lib.UInt8Array object at 0x7f9434595d80>
[
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 IOリーダーに統合されているIO読み取り機能も提供しています。以下の関数は、IOソースからの読み取りを高速化するためにPyArrowにディスパッチできるengineキーワードを提供します。
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
デフォルトでは、これらの関数および他のすべてのIOリーダー関数は、NumPyをバックエンドとするデータを返します。これらのリーダーは、dtype_backend="pyarrow"パラメーターを指定することで、PyArrowをバックエンドとするデータを返すことができます。リーダーは、必ずしもPyArrowをバックエンドとするデータを返すためにengine="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
いくつかの非IOリーダー関数も、dtype_backend引数を使用してPyArrowをバックエンドとするデータを返すことができます。これには以下が含まれます。