Mengurangi memori bukan satu langkah tunggal, melainkan alur kerja: ukur dulu peta memori per kolom, identifikasi kolom mana yang boros, turunkan dengan teknik yang aman, lalu verifikasi nilai tidak berubah. Dua teknik utamanya sudah kita kenal dari Chapter sebelumnya — pd.to_numeric(downcast=...) untuk kolom angka dan astype("category") untuk teks berulang — dan Chapter ini menyatukannya menjadi satu fungsi yang dapat dipakai ulang. Pada 100.000 baris transaksi, kombinasi keduanya menekan konsumsi memori lima kali lipat tanpa kehilangan satu nilai pun.
Alur Kerja Empat Langkah #
- Ukur: jalankan
df.memory_usage(deep=True)dan jumlahkan hasilnya; methoddf.info(memory_usage="deep")memberi ringkasan satu baris. - Peta: bandingkan ukuran per kolom — kolom
strdengan banyak pengulangan biasanya paling boros. - Turunkan: downcast kolom integer dengan
pd.to_numeric(downcast="integer"), konversi teks berulang kecategory. - Verifikasi: pastikan jumlah baris, jumlah nilai, dan isi kolom tetap sama sebelum mengganti DataFrame lama.
Penerapan Lengkap pada Satu Tabel #
Skrip berikut menjalankan keempat langkah itu pada tabel transaksi yang sama dari awal Section ini:
import io
import numpy as np
import pandas as pd
rng = np.random.default_rng(42)
n = 100_000
df = pd.DataFrame(
{
"kota": rng.choice(["Jakarta", "Bandung", "Surabaya", "Medan", "Semarang"], size=n),
"produk": rng.choice(
["Beras", "Minyak Goreng", "Gula Pasir", "Kopi", "Telur", "Tepung Terigu", "Sabun", "Sarden"],
size=n,
),
"jumlah": rng.integers(1, 11, size=n),
"harga": rng.choice([15000, 25000, 40000, 55000, 70000], size=n),
}
)
df["total"] = df["jumlah"] * df["harga"]
# 1. Ukur: peta memori per bagian
mu = df.memory_usage(deep=True)
print(mu.to_string())
print("total:", f"{int(mu.sum()):,}", "byte")
print()
# 2. Ringkasan satu baris via info()
buf = io.StringIO()
df.info(memory_usage="deep", buf=buf)
print(buf.getvalue())
print()
# 3. Turunkan: downcast numeric + category utk teks berulang
def turunkan_memori(d):
out = d.copy()
for kolom in out.columns:
if pd.api.types.is_integer_dtype(out[kolom]):
out[kolom] = pd.to_numeric(out[kolom], downcast="integer")
elif out[kolom].dtype == "str" and out[kolom].nunique() <= 0.5 * len(out):
out[kolom] = out[kolom].astype("category")
return out
df_hemat = turunkan_memori(df)
print("dtype sesudah :", df_hemat.dtypes.astype(str).to_dict())
print("total sesudah :", f"{int(df_hemat.memory_usage(deep=True).sum()):,}", "byte")
print("rasio:", round(int(df.memory_usage(deep=True).sum()) / int(df_hemat.memory_usage(deep=True).sum()), 1))
print()
# 4. Verifikasi: nilai tidak berubah
print("kota sama:", df["kota"].equals(df_hemat["kota"].astype(str)))
print("produk sama:", df["produk"].equals(df_hemat["produk"].astype(str)))
print("sum total sama:", int(df["total"].sum()) == int(df_hemat["total"].sum()))
print("banyak baris sama:", len(df) == len(df_hemat))Output yang Dihasilkan:
Index 132
kota 1499235
produk 1563307
jumlah 800000
harga 800000
total 800000
total: 5,462,674 byte
<class 'pandas.DataFrame'>
RangeIndex: 100000 entries, 0 to 99999
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 kota 100000 non-null str
1 produk 100000 non-null str
2 jumlah 100000 non-null int64
3 harga 100000 non-null int64
4 total 100000 non-null int64
dtypes: int64(3), str(2)
memory usage: 5.2 MB
dtype sesudah : {'kota': 'category', 'produk': 'category', 'jumlah': 'int8', 'harga': 'int32', 'total': 'int32'}
total sesudah : 1,100,334 byte
rasio: 5.0
kota sama: True
produk sama: True
sum total sama: True
banyak baris sama: TrueMari kita telaah baris-baris pentingnya:
- Baris 22-24 (peta memori): dua kolom
strmendominasi —kota1.499.235 byte danproduk1.563.307 byte — sementara tiga kolomint64masing-masing 800.000 byte. Total 5.462.674 byte untuk 100.000 baris. - Baris 28-30 (ringkasan
info()): methoddf.info(memory_usage="deep", buf=...)mencetak ringkasan yang ditampung keio.StringIO; baris akhirnya melaporkanmemory usage: 5.2 MB— angka yang sama dengan hasil penjumlahan peta memori. - Baris 34-41 (fungsi
turunkan_memori()): setiap kolom dicek satu kali: kolom integer diturunkan otomatis olehpd.to_numeric(downcast="integer")—jumlahmenjadiint8,hargadantotalmenjadiint32— sedangkan kolomstrdengan kardinalitas di bawah 50% baris dikonversi kecategory. - Baris 43-46 (hasil): dtype akhir
{'kota': 'category', 'produk': 'category', 'jumlah': 'int8', 'harga': 'int32', 'total': 'int32'}menekan total menjadi 1.100.334 byte — rasio 5.0 dibanding kondisi awal. - Baris 50-53 (verifikasi): keempat pemeriksaan menghasilkan
True— isikotadanproduksama setelah dikembalikan kestr, jumlahtotalsama, dan jumlah baris tidak berubah. Tanpa langkah ini, penurunan dtype bisa menyelipkan kesalahan senyap.
Diagnosis dan Obatnya #
| Gejala di peta memori | Penyebab | Obat |
|---|---|---|
Kolom str terbesar, nilai berulang | teks utuh per baris | astype("category") |
Kolom int64 untuk nilai kecil | pandas memilih 8 byte bawaan | pd.to_numeric(downcast="integer") |
Kolom float64 untuk pengukuran | presisi berlebih | pd.to_numeric(downcast="float") |
Kolom datetime64 penuh NaT | parsing gagal | perbaiki parsing, bukan memori |
| Duplikat baris menumpuk | data mentah belum bersih | drop_duplicates() |
Dengan pola ini, tabel yang sama kini bisa diproses dengan lima kali lebih sedikit memori. Untuk data yang tetap terlalu besar untuk masuk memori sekaligus, strateginya berubah bentuk: membaca data secara bertahap — itulah topik Chapter berikutnya tentang chunksize pada read_csv().
Referensi resmi untuk pendalaman: pandas.DataFrame.memory_usage , pandas.DataFrame.info , dan pandas.to_numeric .