Backend pyarrow pada chapter sebelumnya memangkas memori data teks, tetapi masih menyimpan satu juta sel apa pun isinya. Ada kelompok data yang menuntut strategi berbeda: matriks one-hot, hasil one-hot encoding, absensi harian, atau skema spesialis yang isinya nyaris seluruhnya nol. Untuk pola “satu nilai mendominasi” ini pandas menyediakan SparseDtype — dtype ekstensi yang menyimpan hanya sel-sel yang berbeda dari satu nilai pengisi (fill value) dan membiarkan sisanya tersirat. Script berikut mengukur penghematannya, menunjukkan jebakan fill value bawaan, lalu menutup dengan pertukaran data bolak-balik dengan scipy.
Menyimpan Hanya yang Berbeda dari fill_value #
Script berikut membuat Series satu juta float berisi nol, lalu mengonversinya menjadi sparse dengan fill value 0.0.
import numpy as np
import pandas as pd
# SparseDtype menyimpan hanya nilai yang berbeda dari fill_value
n = 1_000_000
padat = pd.Series(np.zeros(n))
jarang = padat.astype(pd.SparseDtype("float64", fill_value=0.0))
print("dtype :", str(jarang.dtype))
print("dense :", f"{padat.memory_usage() / 1e6:.1f} MB")
print("sparse :", f"{jarang.memory_usage() / 1e3:.1f} KB")
print("npoints:", jarang.sparse.npoints)
print()
# default fill_value untuk float adalah NaN, bukan 0
tanpa_fill = padat.astype("Sparse[float64]")
print("astype('Sparse[float64]') ->", str(tanpa_fill.dtype))
print("npoints tanpa fill 0 :", tanpa_fill.sparse.npoints)
print()
# density, sp_values, dan konversi balik
s = pd.Series([0, 7, 0, 0, 5, 0], dtype="Sparse[int64]")
print("dtype :", str(s.dtype))
print("density :", s.sparse.density)
print("sp_values:", s.values.sp_values.tolist())
print("to_dense :", s.sparse.to_dense().tolist())
print("s + 1 :", (s + 1).sparse.to_dense().tolist())
print()
# scipy: coo_matrix <-> DataFrame sparse
from scipy import sparse as sps
mat = sps.coo_matrix(([1.0, 2.0], ([0, 2], [1, 0])), shape=(3, 3))
df_sp = pd.DataFrame.sparse.from_spmatrix(mat)
print(df_sp)
kembali = df_sp.sparse.to_coo()
print("kembali ke scipy:", type(kembali).__name__, "| nnz:", kembali.nnz)Output yang Dihasilkan:
dtype : Sparse[float64, 0.0]
dense : 8.0 MB
sparse : 0.1 KB
npoints: 0
astype('Sparse[float64]') -> Sparse[float64, nan]
npoints tanpa fill 0 : 1000000
dtype : Sparse[int64, 0]
density : 0.3333333333333333
sp_values: [7, 5]
to_dense : [0, 7, 0, 0, 5, 0]
s + 1 : [1, 8, 1, 1, 6, 1]
0 1 2
0 NaN 1.0 NaN
1 NaN NaN NaN
2 2.0 NaN NaN
kembali ke scipy: coo_matrix | nnz: 2Mari kita bedah bagian pentingnya:
- Baris 5-7 (konversi):
pd.SparseDtype("float64", fill_value=0.0)menyatakan “tipe dasarnya float64 dan nilai pengisinya 0.0”;astype()menerima objek dtype ini sebagaimana menerima nama dtype string. - Baris 8-11 (hasil ukuran): representasi
densemenempati 8.0 MB (satu juta × 8 byte), sedangkan versi sparse tinggal 0.1 KB dengannpointsbernilai 0 — tidak ada satu pun sel yang perlu disimpan karena semuanya sama dengan fill value. - Baris 15-17 (jebakan default):
astype("Sparse[float64]")tanpa dtype eksplisit menghasilkanSparse[float64, nan]dannpoints-nya satu juta; tanpa fill value yang tepat, tidak ada penghematan sama sekali. - Baris 21-26 (anatomi): Series
[0, 7, 0, 0, 5, 0]memakaiSparse[int64]yang fill value default-nya0; method.sparse.densitymenghitung rasio data tersimpan (2 dari 6 = 0.33),.values.sp_valuesmembuka array[7, 5]yang memang disimpan, danto_dense()mengembalikan wujud penuhnya. - Baris 32-36 (scipy):
pd.DataFrame.sparse.from_spmatrix()mengubahcoo_matrixscipy menjadi DataFrame sparse, danto_coo()mengembalikannya —nnztetap 2.
fill_value Menentukan Semuanya #
Fill value adalah jantung dtype sparse: sel bernilai persis sama dengan fill value tidak disimpan, dan sisanya disimpan sebagai sp_values beserta posisi indeksnya. Karena itu pemilihan fill value harus mengikuti data, bukan kebiasaan. Output blok kedua memperlihatkan akibatnya: string dtype "Sparse[float64]" bawaan pandas memakai nan sebagai fill value (mengikuti konvensi missing float), sehingga jutaan angka nol tetap tersimpan satu per satu dan memori justru bertambah. Kebalikannya terjadi pada "Sparse[int64]" yang default fill-nya 0 — kebetulan tepat untuk data one-hot.
Pola aman yang direkomendasikan tulisan ini adalah selalu menuliskan fill value secara eksplisit lewat pd.SparseDtype(..., fill_value=...) seperti baris 7. Ciri dtype hasilnya langsung terbaca pada repr: Sparse[float64, 0.0] berarti float64 dengan pengisi 0.0.
Bekerja dengan Accessor .sparse #
Operasi matematika pada Series sparse tetap berjalan seperti biasa: s + 1 menghasilkan [1, 8, 1, 1, 6, 1] dan hasilnya sendiri masih sparse (fill value-nya bergeser ikut menjadi 1). Saat perlu kembali ke dunia dense, s.sparse.to_dense() mengembalikan Series biasa. Accessor .sparse menyediakan kumpulan method khusus: density untuk rasio kelengkapan, npoints untuk jumlah nilai tersimpan, to_dense() untuk konversi balik, dan pada Series dengan MultiIndex tersedia to_coo() untuk ekspor ke format scipy.
Nilai density berguna sebagai penentu kapan sparse memang tepat. Sebagai pegangan praktis, sparse menguntungkan ketika density jauh di bawah 0.5 dan fill value benar-benar mendominasi; pada density mendekati satu, overhead indeks posisi justru membuat representasi sparse lebih berat daripada dense.
Pertukaran dengan scipy #
Ekosistem Python punya pustaka sparse terstandar, scipy.sparse, yang dipakai scikit-learn dan banyak pustaka lain. Dua jembatan pandas membuat pertukarannya satu baris: pd.DataFrame.sparse.from_spmatrix(mat) menarik matriks scipy masuk ke DataFrame (output menampilkan isi 1.0 dan 2.0 di posisi [0, 1] dan [2, 0], sisanya NaN karena fill value default dari jalur ini adalah nan), sedangkan df_sp.sparse.to_coo() mengirim DataFrame sparse kembali ke scipy sebagai coo_matrix dengan nnz yang tetap 2. Perhatikan bahwa fill value hasil from_spmatrix adalah nan — bila Anda ingin nol sebagai pengisi, tulis ulang dtype-nya lewat astype(pd.SparseDtype("float64", fill_value=0.0)).
Dengan sparse, seluruh keluarga dtype ekstensi pada section ini sudah lengkap dari sisi penyimpanan. Satu risiko baru muncul dari kekayaan API sebanyak itu: API berubah antar versi pandas, dan chapter penutup ini — sekaligus penutup section Advanced Pandas — membahas bagaimana pandas mengumumkan perubahannya lewat kebijakan deprecation, warning, dan halaman whatsnew.
Referensi resmi untuk chapter ini: user guide Sparse data structures , pandas.SparseDtype , dan pandas.DataFrame.sparse.from_spmatrix .