dtype adalah properti yang paling sering berubah tanpa memberi tahu kita. Satu sel kosong di CSV bisa mengubah kolom int64 menjadi float64; satu operasi gabung bisa mengubah kolom integer menjadi teks; dan astype yang salah menebak langsung melempar error. Chapter ini melatih cara memeriksa dtype dengan df.dtypes dan Series.dtype, memahami kenapa kolom integer berubah menjadi float64, serta membaca error konversi agar perbaikannya tepat sasaran.

Membaca dtype dengan Dua Pintu #

pandas menyediakan dua tampilan yang saling melengkapi. df.dtypes mengembalikan satu Series yang berisi dtype setiap kolom, cocok untuk melihat keseluruhan bentuk data sekaligus. df["nama"].dtype membaca dtype satu kolom saja, cocok untuk perbandingan satu-satu di dalam skrip. Keduanya baca-saja, jadi kita bisa memanggilnya kapan pun tanpa risiko mengubah data. Pemeriksaan dtype paling efektif dilakukan tepat setelah membaca data, sebelum transformasi lain menutupi jejaknya. Script berikut membaca CSV transaksi toko, membandingkan hasilnya dengan bentuk yang diharapkan, lalu menunjukkan cara memulihkan dtype yang bergeser.

python
import pandas as pd
from io import StringIO

csv = """kode,nama,jumlah,harga_satuan
TRX-001,Budi,2,15000
TRX-002,Siti,,20000
TRX-003,Dewi,1,
TRX-004,Rian,5,12000"""

transaksi = pd.read_csv(StringIO(csv))
harapan = pd.DataFrame({"jumlah": [2, 3, 1, 5]})


def banding_dtype(kiri: pd.Series, kanan: pd.Series, label: str) -> None:
    """Cetak label ketika dtype dua Series tidak sama."""
    if kiri.dtype != kanan.dtype:
        print(f"{label}: {kiri.dtype} vs {kanan.dtype}")


print("--- dtype hasil read_csv ---")
print(transaksi.dtypes.to_dict())
print("baris yang memuat NaN:")
print(transaksi[transaksi.isna().any(axis=1)].to_string(index=False))
print()

print("--- df.dtypes vs Series.dtype ---")
print("df.dtypes        ->", type(transaksi.dtypes).__name__)
print("df['jumlah'].dtype ->", transaksi["jumlah"].dtype)
print()

print("--- teks memakai dtype str bawaan 3.0 ---")
print("dtype kolom nama :", transaksi["nama"].dtype)
print("sama dengan 'str'?", transaksi["nama"].dtype == "str")
print()

print("--- membandingkan dtype dengan frame harapan ---")
banding_dtype(transaksi["jumlah"], harapan["jumlah"], "jumlah")
print("penyebabnya: NaN di kolom jumlah menaikkan int64 menjadi float64")
print()

print("--- convert_dtypes memulihkan integer ---")
print(transaksi.convert_dtypes().dtypes.to_dict())
print()

print("--- astype yang ditolak ---")
teks = pd.Series(["10", "2x"])
try:
    teks.astype(int)
except ValueError as exc:
    print("astype(int)   ->", str(exc).splitlines()[0])
try:
    teks.astype(float)
except ValueError as exc:
    print("astype(float) ->", str(exc).splitlines()[0])
print("to_numeric coerce:", pd.to_numeric(teks, errors="coerce").tolist())

Output yang Dihasilkan:

text
--- dtype hasil read_csv ---
{'kode': <StringDtype(na_value=nan)>, 'nama': <StringDtype(na_value=nan)>, 'jumlah': dtype('float64'), 'harga_satuan': dtype('float64')}
baris yang memuat NaN:
   kode nama  jumlah  harga_satuan
TRX-002 Siti     NaN       20000.0
TRX-003 Dewi     1.0           NaN

--- df.dtypes vs Series.dtype ---
df.dtypes        -> Series
df['jumlah'].dtype -> float64

--- teks memakai dtype str bawaan 3.0 ---
dtype kolom nama : str
sama dengan 'str'? True

--- membandingkan dtype dengan frame harapan ---
jumlah: float64 vs int64
penyebabnya: NaN di kolom jumlah menaikkan int64 menjadi float64

--- convert_dtypes memulihkan integer ---
{'kode': <StringDtype(na_value=<NA>)>, 'nama': <StringDtype(na_value=<NA>)>, 'jumlah': Int64Dtype(), 'harga_satuan': Int64Dtype()}

--- astype yang ditolak ---
astype(int)   -> invalid literal for int() with base 10: '2x'
astype(float) -> could not convert string to float: '2x'
to_numeric coerce: [10.0, nan]

Mari kita bedah bagian pentingnya:

  1. transaksi.dtypes.to_dict(): kolom jumlah dan harga_satuan terbaca sebagai float64, bukan integer. Penyebabnya terlihat pada dua baris ber-NaN: sel kosong milik Siti di kolom jumlah dan sel kosong milik Dewi di kolom harga_satuan. NaN tidak punya representasi integer, sehingga pandas memilih float64 yang bisa menampungnya.
  2. type(transaksi.dtypes).__name__: hasilnya Series, mengingatkan kita bahwa df.dtypes adalah objek pandas biasa yang bisa diindex, dibandingkan, atau dijadikan mask seperti Series lainnya.
  3. transaksi["nama"].dtype == "str": di pandas 3.0, kolom teks bawaan memakai dtype str (bukan object seperti versi lama), dan nilai hilangnya NaN. Pemeriksaan teks yang lama seperti dtype == object akan melaporkan False pada data 3.0 yang bersih.
  4. Fungsi banding_dtype(): helper kecil yang membandingkan dtype dua Series dan mencetak baris laporan hanya saat keduanya berbeda. Pola “bandingkan dengan bentuk harapan” inilah inti debugging dtype: hasil pembacaan dibandingkan terhadap kontrak, bukan terhadap perasaan.
  5. transaksi.convert_dtypes(): memulihkan kolom yang isinya tetap bulat menjadi dtype nullable Int64 — jumlah dan harga_satuan kembali terbaca sebagai integer sambil tetap menampung NaN. Perhatikan kolom teks ikut berpindah ke dtype string dengan nilai hilang pd.NA, jadi konversi ini juga mengubah perilaku perbandingan nilai hilang.
  6. teks.astype(int): melempar ValueError dengan pesan invalid literal for int() with base 10: '2x'. Pesan itu menunjuk nilai persis yang gagal, sehingga perbaikan bisa diarahkan ke baris data tersebut. Alternatif yang lebih toleran adalah pd.to_numeric(teks, errors="coerce"), yang mengubah nilai bermasalah menjadi NaN dan melanjutkan proses.

Peta Perbaikan dtype yang Sering Dibutuhkan #

SituasiAlat yang tepat
Kolom angka jadi float64 karena NaNconvert_dtypes() untuk kembali ke Int64, atau fillna() bila NaN memang harus diisi
Teks angka yang bersihastype(int) / astype(float)
Teks angka yang mungkin kotorpd.to_numeric(..., errors="coerce") lalu periksa NaN yang baru muncul
Ingin melihat dtype sekaligus jumlah baris terisidf.info()

dtype yang tidak sesuai harapan adalah salah satu bentuk “kode benar, data salah”. Masalah sebaliknya — kode yang belum terbukti benar — membutuhkan pengujian terprogram, dan itulah materi section ini pada chapter berikutnya: Menguji DataFrame dengan pytest.

Referensi resmi untuk chapter ini: pandas.DataFrame.dtypes , pandas.DataFrame.convert_dtypes , dan Working with missing data .