0Pricing
Pandas & NumPy Academy · Pelajaran

Menghindari iterrows dan Perulangan Python

Ganti perulangan baris demi baris dengan operasi kolom tervectorisasi, np.where, dan pd.cut untuk mencapai percepatan 10–100 kali.

Menghindari iterrows dan Perulangan Python adalah pelajaran Pandas & NumPy Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Pandas & NumPy Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Pandas & NumPy Academy mencakup 4 pelajaran total.

Biaya Iterasi Baris demi Baris

Pandas dibangun di atas NumPy, yang memproses seluruh array sekaligus menggunakan kode C terkompilasi. Saat Anda melakukan iterasi baris demi baris dengan for _, row in df.iterrows(), Anda melewati mekanisme tersebut dan kembali ke Python murni — setiap baris diekstrak sebagai objek Series, dan loop berjalan di interpreter Python dengan biaya sekitar 100–1000 kali lebih besar daripada operasi bervectorisasi yang setara. Untuk DataFrame berisi 1 juta baris, hal ini dapat berarti hitungan menit, bukan milidetik.

import pandas as pd
import numpy as np
import timeit

np.random.seed(0)
df = pd.DataFrame({'a': np.random.randn(10000), 'b': np.random.randn(10000)})

# Slow: iterrows loop
def loop_version(df):
    result = []
    for _, row in df.iterrows():
        result.append(row['a'] + row['b'])
    return pd.Series(result)

# Fast: vectorised
t_loop = timeit.timeit(lambda: loop_version(df), number=5)
t_vec = timeit.timeit(lambda: df['a'] + df['b'], number=500)

print(f'Loop (5 runs):       {t_loop:.3f}s total')
print(f'Vectorised (500 runs): {t_vec:.3f}s total')
print(f'Speedup: ~{(t_loop/5)/(t_vec/500):.0f}x')

Ganti Loop Kondisional dengan np.where

np.where(condition, value_if_true, value_if_false) adalah padanan bervectorisasi dari if/else per elemen. Alih-alih melakukan iterasi pada baris dan menulis pernyataan if, berikan kondisi serta kedua nilai hasil sebagai array. np.where menghitungnya dalam C untuk seluruh kolom sekaligus, sehingga 50–200 kali lebih cepat daripada loop Python yang setara untuk DataFrame berukuran besar.

import pandas as pd
import numpy as np
import timeit

np.random.seed(0)
df = pd.DataFrame({'price': np.random.uniform(10, 100, 100000)})

# Slow: iterrows
def label_loop(df):
    labels = []
    for _, row in df.iterrows():
        if row['price'] > 50:
            labels.append('expensive')
        else:
            labels.append('cheap')
    return labels

# Fast: np.where
def label_vectorised(df):
    return np.where(df['price'] > 50, 'expensive', 'cheap')

# Verify equivalence on a small subset
assert list(label_loop(df.head(100))) == list(label_vectorised(df.head(100)))
print('Results match!')
print('Fast version result sample:', label_vectorised(df)[:5])

Beberapa Kondisi dengan np.select

Untuk tiga kondisi atau lebih, gunakan np.select(condlist, choicelist, default=), bukan np.where bertingkat. Berikan daftar array boolean dan daftar nilai keluaran yang sesuai. Kondisi pertama yang cocok menentukan keluaran; baris yang tidak cocok mendapatkan nilai default. Cara ini menggantikan rangkaian if/elif/else yang kompleks di dalam loop dengan ekspresi yang bersih dan bervectorisasi.

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({'score': np.random.randint(0, 101, 20)})

conditions = [
    df['score'] >= 90,
    df['score'] >= 75,
    df['score'] >= 60
]
choices = ['A', 'B', 'C']

df['grade'] = np.select(conditions, choices, default='F')
print(df.sort_values('score', ascending=False).head(10))

Operasi String Bervectorisasi melalui .str

Manipulasi string merupakan sumber umum loop yang lambat. Pengakses .str dari Pandas menyediakan padanan bervectorisasi untuk semua metode string Python: .str.lower(), .str.strip(), .str.replace(), .str.contains(), dan banyak lagi. Menggunakan metode .str 10–50 kali lebih cepat daripada melakukan iterasi pada baris dan memanggil metode string Python secara manual.

import pandas as pd
import numpy as np
import timeit

np.random.seed(0)
names = ['Alice Smith', 'BOB JONES', '  carol  ', 'Dave Brown'] * 25000
df = pd.DataFrame({'name': names})

# Slow: loop
def clean_loop(df):
    return [n.strip().title() for n in df['name']]

# Fast: .str accessor
def clean_vectorised(df):
    return df['name'].str.strip().str.title()

t1 = timeit.timeit(lambda: clean_loop(df), number=10)
t2 = timeit.timeit(lambda: clean_vectorised(df), number=50)

print(f'Loop (10 runs): {t1:.3f}s')
print(f'.str (50 runs): {t2:.3f}s')
print(f'Speedup: {(t1/10)/(t2/50):.0f}x')
print('Sample:', clean_vectorised(df).head(4).tolist())

Menggunakan pd.cut dan pd.qcut sebagai Pengganti Loop

pd.cut() dan pd.qcut() melakukan vektorisasi operasi pengelompokan ke dalam interval yang sering ditulis sebagai loop dengan beberapa kondisi if/elif. Jika Anda mendapati diri menulis 'if value < 18: age_group = child elif value < 65: age_group = adult' di dalam loop baris, gantilah dengan satu pemanggilan pd.cut() yang memproses seluruh kolom sekaligus dengan kecepatan C.

import pandas as pd
import numpy as np
import timeit

np.random.seed(0)
df = pd.DataFrame({'age': np.random.randint(0, 90, 100000)})

# Slow: loop with conditionals
def categorise_loop(df):
    result = []
    for age in df['age']:
        if age < 18:
            result.append('child')
        elif age < 65:
            result.append('adult')
        else:
            result.append('senior')
    return result

# Fast: pd.cut
def categorise_cut(df):
    return pd.cut(df['age'], bins=[0, 18, 65, 100],
                  labels=['child', 'adult', 'senior'],
                  right=False)

assert list(categorise_loop(df.head(5))) == list(categorise_cut(df.head(5)).astype(str))
print('Fast version sample:', categorise_cut(df).head(5).tolist())

apply() Tidak Selalu Menjadi Jawaban

Banyak tutorial menyarankan untuk mengganti loop dengan .apply(func), tetapi apply secara internal masih merupakan loop pada tingkat Python — kecepatannya hanya sedikit lebih tinggi daripada iterrows dan jauh lebih lambat daripada vektorisasi yang sebenarnya. Gunakan apply hanya jika tidak ada alternatif bervectorisasi (logika kompleks yang melibatkan beberapa kolom). Jika fungsi bawaan Pandas atau NumPy dapat menyatakan operasi tersebut, selalu pilih fungsi itu daripada apply.

import pandas as pd
import numpy as np
import timeit

np.random.seed(0)
df = pd.DataFrame({'x': np.random.randn(100000)})

# These all do the same thing — compare performance
t1 = timeit.timeit(lambda: df['x'].apply(lambda v: v**2), number=20)
t2 = timeit.timeit(lambda: df['x'] ** 2, number=200)
t3 = timeit.timeit(lambda: np.square(df['x']), number=200)

print(f'apply(v**2): {t1/20*1000:.2f} ms per run')
print(f'** operator: {t2/200*1000:.2f} ms per run')
print(f'np.square(): {t3/200*1000:.2f} ms per run')

Mengganti Loop groupby dengan agg dan transform

Pola yang umum adalah melakukan iterasi pada grup secara manual: for name, group in df.groupby('cat'): do_something(group). Cara ini lambat karena alasan yang sama dengan lambatnya iterasi baris. Gantilah dengan groupby().agg() untuk menghasilkan statistik ringkasan, atau groupby().transform() untuk menyiarkan statistik tingkat grup kembali ke posisi baris semula.

import pandas as pd
import numpy as np
import timeit

np.random.seed(0)
df = pd.DataFrame({
    'cat': np.random.choice(['A','B','C','D'], 100000),
    'val': np.random.randn(100000)
})

# Slow: manual loop to add group mean
def slow_group_mean(df):
    means = {}
    for name, group in df.groupby('cat'):
        means[name] = group['val'].mean()
    return df['cat'].map(means)

# Fast: transform
def fast_group_mean(df):
    return df.groupby('cat')['val'].transform('mean')

t1 = timeit.timeit(lambda: slow_group_mean(df), number=10)
t2 = timeit.timeit(lambda: fast_group_mean(df), number=100)
print(f'Loop:       {t1/10*1000:.1f} ms')
print(f'transform:  {t2/100*1000:.1f} ms')
print(f'Speedup: {(t1/10)/(t2/100):.0f}x')

Kapan iterrows Dapat Diterima

Meskipun lambat, ada penggunaan yang wajar untuk iterrows dan itertuples: mencetak atau mencatat informasi dari baris (kinerja tidak relevan), menyusun payload API ketika setiap baris memicu pemanggilan HTTP (latensi jaringan lebih dominan), dan men-debug baris tertentu dengan kondisi yang kompleks. Jika Anda memiliki kurang dari 1.000 baris dan operasi hanya dijalankan sekali, perbedaan antara loop dan vektorisasi hanya beberapa milidetik — tidak sebanding dengan kompleksitas kodenya.

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'order_id': [101, 102, 103],
    'product': ['Widget', 'Gadget', 'Doohickey'],
    'amount': [29.99, 49.99, 9.99]
})

# Acceptable use: building a structured log (small data, one-time)
for _, row in df.iterrows():
    print(f'Order {row["order_id"]}: {row["product"]} — ${row["amount"]:.2f}')

itertuples Lebih Cepat daripada iterrows

Jika Anda harus melakukan iterasi pada baris di Python (karena tidak ada padanan bervectorisasi), gunakan itertuples(), bukan iterrows(). Fungsi ini mengembalikan setiap baris sebagai tuple bernama, bukan Series Pandas, sehingga menghindari biaya pembuatan Series. Hasilnya biasanya 5–10 kali lebih cepat daripada iterrows. Akses nilainya dengan notasi atribut: row.column_name. Hindari cara ini jika nama kolom mengandung spasi (bukan nama atribut yang valid).

import pandas as pd
import numpy as np
import timeit

np.random.seed(0)
df = pd.DataFrame({'a': np.random.randn(10000), 'b': np.random.randn(10000)})

t1 = timeit.timeit(
    lambda: [row.a + row.b for row in df.itertuples()], number=10)
t2 = timeit.timeit(
    lambda: [row['a'] + row['b'] for _, row in df.iterrows()], number=10)

print(f'itertuples: {t1/10*1000:.1f} ms')
print(f'iterrows:   {t2/10*1000:.1f} ms')
print(f'itertuples speedup: {t2/t1:.1f}x')

Daftar Periksa Pola Vektorisasi

Sebelum menulis loop, ajukan pertanyaan berikut:

  • Apakah operasinya dilakukan per elemen pada satu kolom? → Gunakan ekspresi aritmetika kolom atau ufunc NumPy.
  • Apakah operasi tersebut melibatkan logika kondisional? → Gunakan np.where (2 kondisi) atau np.select (3+).
  • Apakah operasi tersebut mengelompokkan nilai ke dalam rentang? → Gunakan pd.cut atau pd.qcut.
  • Apakah operasi tersebut menerapkan operasi string? → Gunakan pengakses .str.
  • Apakah operasi tersebut melakukan agregasi dalam grup? → Gunakan groupby().agg() atau groupby().transform().
Gunakan apply() atau itertuples() hanya jika tidak ada pilihan di atas yang berlaku.

Contoh Peningkatan Kecepatan Nyata: Penghitungan Harga

Berikut refaktor lengkap sebelum dan sesudah untuk penghitungan bisnis yang umum — menerapkan diskon bertingkat berdasarkan jumlah pesanan. Versi loop mudah dibaca, tetapi sangat lambat untuk DataFrame berukuran besar. Versi bervectorisasi yang menggunakan np.select menghasilkan hasil yang sama dalam sepersepuluh waktu.

import pandas as pd
import numpy as np
import timeit

np.random.seed(0)
df = pd.DataFrame({
    'price': np.random.uniform(10, 200, 100000),
    'qty': np.random.randint(1, 500, 100000)
})

# BEFORE: loop with conditionals
def slow_discount(df):
    result = []
    for _, row in df.iterrows():
        if row['qty'] >= 100:
            disc = 0.2
        elif row['qty'] >= 50:
            disc = 0.1
        elif row['qty'] >= 10:
            disc = 0.05
        else:
            disc = 0.0
        result.append(row['price'] * (1 - disc))
    return pd.Series(result)

# AFTER: np.select
def fast_discount(df):
    conditions = [df['qty'] >= 100, df['qty'] >= 50, df['qty'] >= 10]
    discounts = [0.20, 0.10, 0.05]
    disc = np.select(conditions, discounts, default=0.0)
    return df['price'] * (1 - disc)

assert slow_discount(df.head(200)).round(4).equals(fast_discount(df.head(200)).reset_index(drop=True).round(4))
print('Both versions agree!')

Pemeriksaan Cepat

Uji pemahaman Anda tentang vektorisasi dari pelajaran ini.

Ringkasan Pelajaran

Dalam pelajaran ini Anda mempelajari bahwa iterrows 100–1000 kali lebih lambat daripada operasi bervectorisasi, np.where dan np.select menggantikan loop kondisional, pengakses .str melakukan vektorisasi operasi string, dan groupby().transform() menggantikan iterasi grup secara manual. Jika Anda harus melakukan iterasi, gunakan itertuples, bukan iterrows, untuk peningkatan 5–10 kali. Berikutnya kita akan membahas tipe data yang efisien — menurunkan ukuran tipe numerik dan menggunakan tipe kategorikal untuk mengurangi memori hingga 70%.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Menghindari iterrows dan Perulangan Python” gratis?

Ya — teks lengkap “Menghindari iterrows dan Perulangan Python” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Pandas & NumPy Academy, upgrade ke CoddyKit PRO. Kursus Pandas & NumPy Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Menghindari iterrows dan Perulangan Python”?

Ganti perulangan baris demi baris dengan operasi kolom tervectorisasi, np.where, dan pd.cut untuk mencapai percepatan 10–100 kali. Kamu berlatih Pandas & NumPy Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Pandas & NumPy Academy?

Tidak diperlukan pengalaman sebelumnya. Pandas & NumPy Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.

Berapa lama pelajaran “Menghindari iterrows dan Perulangan Python” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Pandas & NumPy Academy ini?

Ya. Setiap pelajaran Pandas & NumPy Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Pemrofilan dengan timeit dan memory_profiler
  2. Menghindari iterrows dan Perulangan Python
  3. Tipe Data Efisien untuk Mengurangi Memori
  4. Membaca File Besar dalam Potongan
← Kembali ke Pandas & NumPy Academy