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 #

  1. Ukur: jalankan df.memory_usage(deep=True) dan jumlahkan hasilnya; method df.info(memory_usage="deep") memberi ringkasan satu baris.
  2. Peta: bandingkan ukuran per kolom — kolom str dengan banyak pengulangan biasanya paling boros.
  3. Turunkan: downcast kolom integer dengan pd.to_numeric(downcast="integer"), konversi teks berulang ke category.
  4. 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:

python
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:

text
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: True

Mari kita telaah baris-baris pentingnya:

  1. Baris 22-24 (peta memori): dua kolom str mendominasi — kota 1.499.235 byte dan produk 1.563.307 byte — sementara tiga kolom int64 masing-masing 800.000 byte. Total 5.462.674 byte untuk 100.000 baris.
  2. Baris 28-30 (ringkasan info()): method df.info(memory_usage="deep", buf=...) mencetak ringkasan yang ditampung ke io.StringIO; baris akhirnya melaporkan memory usage: 5.2 MB — angka yang sama dengan hasil penjumlahan peta memori.
  3. Baris 34-41 (fungsi turunkan_memori()): setiap kolom dicek satu kali: kolom integer diturunkan otomatis oleh pd.to_numeric(downcast="integer") — jumlah menjadi int8, harga dan total menjadi int32 — sedangkan kolom str dengan kardinalitas di bawah 50% baris dikonversi ke category.
  4. 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.
  5. Baris 50-53 (verifikasi): keempat pemeriksaan menghasilkan True — isi kota dan produk sama setelah dikembalikan ke str, jumlah total sama, dan jumlah baris tidak berubah. Tanpa langkah ini, penurunan dtype bisa menyelipkan kesalahan senyap.

Diagnosis dan Obatnya #

Gejala di peta memoriPenyebabObat
Kolom str terbesar, nilai berulangteks utuh per barisastype("category")
Kolom int64 untuk nilai kecilpandas memilih 8 byte bawaanpd.to_numeric(downcast="integer")
Kolom float64 untuk pengukuranpresisi berlebihpd.to_numeric(downcast="float")
Kolom datetime64 penuh NaTparsing gagalperbaiki parsing, bukan memori
Duplikat baris menumpukdata mentah belum bersihdrop_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 .