Keluarga nullable pada chapter sebelumnya berjalan di atas penyimpanan milik pandas sendiri. Ada mesin penyimpanan kedua yang resmi didukung pandas 3.0: Apache Arrow, pustaka kolom in-memory yang juga menopang format Parquet. pandas mengeksposnya lewat dua pintu: nama dtype eksplisit seperti string[pyarrow] dan int64[pyarrow], serta argumen dtype_backend="pyarrow" pada pembaca berkas seperti read_csv(). Hadiah utamanya adalah memori — pada data teks besar, penyimpanan Arrow bisa tiga kali lebih ringkas daripada object. Script berikut menguji ketiga hal itu berurutan di lingkungan kita (pandas 3.0.6 dengan pyarrow 26.0.0 yang terpasang bersama).
dtype pyarrow Eksplisit #
Cara paling langsung memakai Arrow adalah menuliskan nama dtype saat membuat Series.
import io
import pandas as pd
# dtype pyarrow eksplisit lewat nama dtype string
s = pd.Series(["Budi", "Siti", None], dtype="string[pyarrow]")
print("string[pyarrow] ->", str(s.dtype), "| storage:", s.dtype.storage, "| na_value:", s.dtype.na_value)
i = pd.Series([1, 2, None], dtype="int64[pyarrow]")
print("int64[pyarrow] ->", str(i.dtype), "| nilai:", i.tolist())
f = pd.Series([1.5, None], dtype="float64[pyarrow]")
print("float64[pyarrow] ->", str(f.dtype))
print()
# "str[pyarrow]" bukan nama dtype yang sah
try:
pd.Series(["a"], dtype="str[pyarrow]")
except TypeError as e:
print("str[pyarrow] ->", type(e).__name__, ":", str(e)[:55])
print()
# dtype_backend="pyarrow" pada read_csv
csv = io.StringIO("id,nama,nilai\n1,Budi,100\n2,Siti,\n3,Dewi,300\n")
df_default = pd.read_csv(csv)
csv.seek(0)
df_arrow = pd.read_csv(csv, dtype_backend="pyarrow")
print("default :", list(df_default.dtypes.astype(str)))
print("pyarrow :", list(df_arrow.dtypes.astype(str)))
print("kolom nilai tetap int meski ada NaN:", str(df_arrow["nilai"].dtype))
print()
# penghematan memori teks pada satu juta baris
n = 1_000_000
teks = pd.Series(["Jakarta", "Bandung", "Surabaya", "Medan"] * (n // 4), dtype="object")
pa = teks.astype("string[pyarrow]")
print("object :", f"{teks.memory_usage(deep=True) / 1e6:.1f} MB")
print("string[pyarrow]:", f"{pa.memory_usage(deep=True) / 1e6:.1f} MB")Output yang Dihasilkan:
string[pyarrow] -> string | storage: pyarrow | na_value: <NA>
int64[pyarrow] -> int64[pyarrow] | nilai: [1, 2, <NA>]
float64[pyarrow] -> double[pyarrow]
str[pyarrow] -> TypeError : data type 'str[pyarrow]' not understood
default : ['int64', 'str', 'float64']
pyarrow : ['int64[pyarrow]', 'string[pyarrow]', 'int64[pyarrow]']
kolom nilai tetap int meski ada NaN: int64[pyarrow]
object : 55.8 MB
string[pyarrow]: 14.8 MBMari kita bedah bagian pentingnya:
- Baris 6-7 (teks Arrow): dtype
string[pyarrow]dicetak sebagaistring— repr-nya sama denganpd.StringDtype()— tetapi atributstoragemembuktikan penyimpanannyapyarrow, danna_value-nya<NA>. - Baris 8-9 (bilangan Arrow):
int64[pyarrow]mempertahankan nama lengkapnya di repr dan menuliskan missing sebagai<NA>, bukanNaN. - Baris 10-11 (float Arrow): dtype
float64[pyarrow]justru dicetakdouble[pyarrow]— pandas mengikuti istilah Arrow yang menamai float 64-bit “double”. - Baris 15-18 (nama yang tidak sah): menuliskan
"str[pyarrow]"ditolakTypeError: data type 'str[pyarrow]' not understood; awalan yang sah untuk teks adalahstring, bukanstr.
dtype_backend=“pyarrow” pada read_csv #
Baris 22-28 membaca CSV yang sama dua kali: pertama dengan pengaturan default, kedua dengan dtype_backend="pyarrow". Perbedaannya terlihat jelas pada daftar dtype:
| Kolom | Default | dtype_backend="pyarrow" |
|---|---|---|
id (bilangan bulat) | int64 | int64[pyarrow] |
nama (teks) | str | string[pyarrow] |
nilai (bulat dengan NaN) | float64 | int64[pyarrow] |
Baris ketiga tabel adalah kejutan yang paling berharga. Pada mode default, satu sel kosong memaksa kolom bilangan bulat naik ke float64 — perilaku yang dibedah pada chapter Extension dtypes. Backend pyarrow tidak mengalami keterbatasan itu: array Arrow menyimpan bitmask null secara terpisah, sehingga kolom nilai tetap int64[pyarrow] meski memuat NaN. Data bulat pun tidak berubah bentuk hanya karena satu sel kosong.
Penghematan Memori pada Data Teks #
Blok terakhir membangun Series satu juta string kota, menyimpannya sebagai object, lalu mengonversinya ke string[pyarrow] dan membandingkan memory_usage(deep=True):
| Representasi | Memori 1 juta string |
|---|---|
object | 55.8 MB |
string[pyarrow] | 14.8 MB |
Angka 55.8 MB menjadi 14.8 MB karena dua hal. Pertama, dtype object menyimpan setiap string sebagai objek Python terpisah dengan kepala objek (overhead) sendiri-sendiri, sementara Arrow menata semua teks berurutan di dalam satu buffer. Kedua, Arrow menyimpan isi string yang sama persis tanpa duplikasi tambahan dan mengindeksnya dengan offset. Untuk kolom kategori yang nilainya sangat berulang, category masih lebih hemat lagi — pembandingan lengkapnya ada pada chapter memilih dtype yang efisien di section Performa dan Efisiensi.
Konversi berjalan dua arah tanpa drama: astype("string[pyarrow]") menurunkan kolom object ke Arrow, dan astype("object") — atau astype("string") — mengembalikannya bila pustaka di hilir belum mendukung dtype Arrow. Karena string[pyarrow] tetap termasuk extension array dari chapter Extension dtypes, semua operasi pandas biasa (masking, groupby, merge) berjalan sama.
Backend Arrow kini sudah Anda genggam untuk teks dan bilangan. Chapter berikutnya melengkapi kotak alat memori dengan kasus ekstrem yang berbeda: data yang nyaris seluruhnya berisi satu nilai, tempat SparseDtype menyimpan hanya pengecualian dan memangkas penggunaan memori hingga ribuan kali.
Referensi resmi untuk chapter ini: user guide PyArrow Functionality , pandas.ArrowDtype , dan pandas.read_csv .
Backend arrow paling terasa di kolom teks: pandas 3.0 sudah menjadikan dtype str bawaan, tetapi data lama berdtype object perlu dimigrasi. Chapter berikutnya menyusun panduan migrasinya lengkap dengan jebakan yang sering muncul.