Setiap kolom DataFrame pada pandas 3.0 membawa lebih dari sekadar tipe data: kolom tersebut membawa aturan sendiri tentang bagaimana nilai missing direpresentasikan. Aturan itu hidup di sistem extension dtypes, kerangka tipe yang memungkinkan pandas menampung str, category, Int64, dtype pyarrow, hingga sparse di bawah satu antarmuka yang sama. Tanpa peta yang jelas, keluarga dtype ini mudah tertukar — misalnya antara str bawaan dan string, dua tipe teks yang menuliskan missing dengan cara berbeda. Chapter ini membacakan peta lengkapnya: cara mengenali dtype ekstensi, metadata na_value milik masing-masing, dan satu perilaku klasik berupa kolom bilangan yang naik menjadi float64 begitu ada missing.

Membaca Peta dtype Ekstensi #

Script berikut menyandingkan delapan Series dengan dtype berbeda, lalu memeriksa satu per satu apakah dtype-nya termasuk extension array. Bagian kedua membuka atribut na_value atau fill_value yang menyimpan penanda missing, dan bagian terakhir menunjukkan kenaikan tipe akibat missing pada bilangan bulat.

python
import pandas as pd

series_uji = {
    "str (default)": pd.Series(["Budi", "Siti", None]),
    "category": pd.Series(["Makanan", "Minuman"], dtype="category"),
    "Int64 nullable": pd.Series([1, None], dtype="Int64"),
    "boolean nullable": pd.Series([True, None], dtype="boolean"),
    "int64[pyarrow]": pd.Series([1, 2, None], dtype="int64[pyarrow]"),
    "string[pyarrow]": pd.Series(["x", None], dtype="string[pyarrow]"),
    "Sparse[int64]": pd.Series([0, 7, 0], dtype="Sparse[int64]"),
    "datetime64[us]": pd.Series(pd.to_datetime(["2026-01-01", None])),
}

for label, s in series_uji.items():
    tipe = str(s.dtype)
    ext = pd.api.types.is_extension_array_dtype(s.dtype)
    print(f"{label:18s} -> {tipe:20s} extension={ext}")
print()

# dtype ekstensi membawa metadata missing sendiri-sendiri
print("str             :", pd.Series(["a", None]).dtype.na_value)
print("string[pyarrow] :", pd.Series(["a", None]).astype("string[pyarrow]").dtype.na_value)
print("Int64           :", pd.Series([], dtype="Int64").dtype.na_value)
print("Sparse[int64]   :", pd.Series([], dtype="Sparse[int64]").dtype.fill_value)
print()

# missing pada int64 numpy memaksa kelas data naik ke float64
angka = pd.Series([1, None, 3])
print(angka.dtype, "->", angka.tolist())
print("pilihan nullable:", angka.astype("Int64").dtype, angka.astype("Int64").tolist())

Output yang Dihasilkan:

text
str (default)      -> str                  extension=True
category           -> category             extension=True
Int64 nullable     -> Int64                extension=True
boolean nullable   -> boolean              extension=True
int64[pyarrow]     -> int64[pyarrow]       extension=True
string[pyarrow]    -> string               extension=True
Sparse[int64]      -> Sparse[int64, 0]     extension=True
datetime64[us]     -> datetime64[us]       extension=False

str             : nan
string[pyarrow] : <NA>
Int64           : <NA>
Sparse[int64]   : 0

float64 -> [1.0, nan, 3.0]
pilihan nullable: Int64 [1, <NA>, 3]

Mari kita bedah bagian pentingnya:

  1. Baris 3-17 (peta dtype): dictionary series_uji pada baris 3-12 berisi delapan Series dengan cara penulisan dtype yang berbeda-beda; loop baris 14-17 mencetak str(s.dtype) beserta hasil pd.api.types.is_extension_array_dtype().
  2. Kolom extension: hampir semua dtype bernilai True — termasuk str, yang pada pandas 3.0 diimplementasikan sebagai extension array. Yang berbeda adalah datetime64[us] dengan False karena dtype itu masih dtype NumPy murni.
  3. Baris 21-24 (metadata missing): setiap dtype membuka penandanya sendiri — str memakai nan, string[pyarrow] dan Int64 memakai <NA> (objek pd.NA), sedangkan Sparse[int64] memakai konsep fill_value berupa nilai yang justru tidak disimpan.
  4. Baris 28-30 (kenaikan tipe): pd.Series([1, None, 3]) tanpa dtype eksplisit menghasilkan float64 karena None memaksa NumPy memilih tipe floating point; astype("Int64") mengembalikan bilangan bulat sekaligus menjaga None sebagai <NA>.

Keluarga dtype pada pandas 3.0 #

Tabel berikut memetakan dtype yang akan sering Anda temui, lengkap dengan penanda missing dan kegunaan utamanya.

dtypePenulisanPenanda missingKapan dipakai
strdefault hasil read_csvNaNteks biasa, hanya menyimpan string
categorydtype="category"NaNnilai berulang dari himpunan kecil
Int64, Float64dtype="Int64"<NA>bilangan dengan missing
booleandtype="boolean"<NA>logika tiga keadaan: True, False, NA
string[pyarrow]dtype="string[pyarrow]"<NA>teks besar yang perlu hemat memori
int64[pyarrow], dst.dtype_backend="pyarrow"<NA>kolom numerik berbasis Arrow
Sparse[int64], dst.pd.SparseDtype(...)fill_valuedata didominasi satu nilai
datetime64[us]pd.to_datetimeNaTdata waktu, resolusi mikrodetik

Empat keluarga pertama adalah dtype milik pandas; dua berikutnya dibangun di atas Apache Arrow; sparse dan datetime masing-masing punya mekanisme khusus yang dibedah pada chapter-chapter tersendiri. Yang menyatukan semuanya adalah antarmuka extension array: semuanya bisa dipakai di astype(), dicek dengan is_extension_array_dtype(), dan mendukung operasi pandas standar.

Metadata na_value Milik Tiap dtype #

Bagian kedua script menampilkan atribut yang jarang disebut tutorial lama: s.dtype.na_value. Nilai inilah yang ditulis pandas ke sel ketika data missing, dan nilainya berbeda antar dtype. Keluarga str dan category memakai nan NumPy, sedangkan keluarga nullable (Int64, boolean, string[pyarrow]) memakai pd.NA. Sparse berbeda lagi: dtype Sparse[int64] tidak punya na_value melainkan fill_value, karena model penyimpanannya adalah “simpan semua yang berbeda dari satu nilai pengisi”.

Perbedaan penanda ini berdampak nyata pada perhitungan. nan adalah float, sehingga perbandingan apa pun dengannya menghasilkan False; pd.NA justru menjalar, sehingga pd.NA == 1 menghasilkan <NA> alih-alih boolean. Chapter berikutnya membahas akibat logika ini secara saksama.

Ketika Missing Memaksa Kenaikan Tipe #

Baris terakhir script mendemonstrasikan perilaku yang sering mengejutkan: kolom int64 yang diberi satu None otomatis berubah menjadi float64, terlihat dari output float64 -> [1.0, nan, 3.0]. Penyebabnya mekanis: array NumPy int64 tidak punya cara menulis missing, sehingga satu-satunya tipe yang mampu menampung 1, 3, dan NaN sekaligus adalah float64. Akibat sampingnya, bilangan bulat sangat besar bisa kehilangan ketelitian, dan semua nilai tampil dengan koma desimal.

astype("Int64") memberi jalan keluar yang terlihat pada output terakhir: [1, <NA>, 3] dengan dtype Int64. Tipe ini menyimpan bilangan bulat murni dan menuliskan missing sebagai pd.NA, sehingga tampilan data kembali bersih. Chapter berikutnya membedah keluarga nullable ini secara utuh — mulai dari pd.NA, method convert_dtypes(), hingga aritmetika yang menjaga missing tetap terlihat.

Referensi resmi untuk chapter ini: pandas.api.types.is_extension_array_dtype , pandas.StringDtype , dan user guide Working with nullable integers .