0Pricing
Pandas & NumPy Academy · Ders

iterrows ve Python Döngülerinden Kaçınma

10-100 kat hızlanma elde etmek için satır satır döngüleri vektörleştirilmiş sütun işlemleri, np.where ve pd.cut ile değiştirin.

iterrows ve Python Döngülerinden Kaçınma, CoddyKit'te ücretsiz bir Pandas & NumPy Academy dersidir. Bu, 4 dersinin 2. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Pandas & NumPy Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Pandas & NumPy Academy kursu toplamda 4 dersten oluşur.

Satır Satır Yinelemenin Maliyeti

Pandas, derlenmiş C kodunu kullanarak dizilerin tamamını tek seferde işleyen NumPy üzerine kuruludur. for _, row in df.iterrows() ile satır satır yineleme yaptığınızda bu avantajı devre dışı bırakır ve saf Python'a dönersiniz. Her satır bir Series nesnesi olarak çıkarılır ve döngü, eşdeğer bir vektörleştirilmiş işlemin maliyetinin yaklaşık 100 ila 1000 katıyla Python yorumlayıcısında çalışır. 1 milyon satırlık bir DataFrame için bu, milisaniyeler yerine dakikalar anlamına gelebilir.

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')

Koşullu Döngüleri np.where ile Değiştirme

np.where(condition, value_if_true, value_if_false), öğe bazında bir if/else yapısının vektörleştirilmiş karşılığıdır. Satırlar üzerinde yineleme yapıp bir if ifadesi yazmak yerine koşulu ve her iki sonuç değerini dizi olarak iletirsiniz. np.where bu işlemi tüm sütun için tek seferde C ile hesaplar; bu da büyük DataFrame nesnelerinde eşdeğer bir Python döngüsünden 50-200 kat daha hızlı olmasını sağlar.

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])

np.select ile Birden Çok Koşul

Üç veya daha fazla koşul için iç içe np.where kullanmak yerine np.select(condlist, choicelist, default=) kullanın. Boole dizilerinden oluşan bir listeyi ve bunlara karşılık gelen çıktı değerlerinden oluşan bir listeyi iletin. Çıktıyı ilk eşleşen koşul belirler; hiçbir koşulla eşleşmeyen satırlar default değerini alır. Bu yaklaşım, döngülerin içindeki karmaşık if/elif/else zincirlerinin yerine temiz ve vektörleştirilmiş bir ifade kullanır.

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))

.str ile Vektörleştirilmiş Dize İşlemleri

Dize işleme, yavaş döngülerin yaygın nedenlerinden biridir. Pandas .str erişicisi, tüm Python dize yöntemlerinin vektörleştirilmiş karşılıklarını sunar: .str.lower(), .str.strip(), .str.replace(), .str.contains() ve daha birçok yöntem. .str yöntemlerini kullanmak, satırlar üzerinde yineleme yapıp Python dize yöntemlerini elle çağırmaktan 10-50 kat daha hızlıdır.

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())

Döngüler Yerine pd.cut ve pd.qcut Kullanma

pd.cut() ve pd.qcut(), genellikle birden çok if/elif koşulu içeren döngülerle yazılan aralıklara ayırma işlemlerini vektörleştirir. Kendinizi bir satır döngüsünün içinde 'if value < 18: age_group = child elif value < 65: age_group = adult' yazarken bulursanız, bunun yerine tüm sütunu C hızında tek seferde işleyen bir pd.cut() çağrısı kullanın.

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() Her Zaman Çözüm Değildir

Birçok eğitim, döngüleri .apply(func) ile değiştirmeyi önerir; ancak apply dahili olarak hâlâ Python düzeyinde bir döngüdür — iterrows yönteminden yalnızca biraz daha hızlıdır ve gerçek vektörleştirmeden çok daha yavaştır. apply yöntemini, vektörleştirilmiş bir alternatifin bulunmadığı durumlara (karmaşık, birden çok sütun içeren mantık) ayırın. İşlem bir yerleşik Pandas veya NumPy işleviyle ifade edilebiliyorsa her zaman apply yerine onu tercih edin.

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')

groupby Döngülerini agg ve transform ile Değiştirme

Yaygın bir yaklaşım, gruplar üzerinde elle yineleme yapmaktır: for name, group in df.groupby('cat'): do_something(group). Bu yöntem, iterrows ile aynı nedenlerle yavaştır. Özet istatistikler üretmek için groupby().agg(), grup düzeyindeki istatistikleri özgün satır konumlarına geri yaymak için ise groupby().transform() kullanın.

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')

iterrows Ne Zaman Kabul Edilebilir

Yavaş olmasına rağmen iterrows ve itertuples için geçerli kullanım alanları vardır: satırlardan bilgi yazdırmak veya günlüğe kaydetmek (performans önemli değildir), her satırın bir HTTP çağrısını tetiklediği API istek gövdeleri oluşturmak (ağ gecikmesi baskındır) ve karmaşık koşullara sahip belirli satırların hatalarını ayıklamak. 1.000'den az satırınız varsa ve işlem bir kez çalışıyorsa, döngü ile vektörleştirme arasındaki fark milisaniyeler düzeyindedir; bunun için kodu karmaşıklaştırmaya değmez.

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, iterrows'dan Daha Hızlıdır

Python'da satırlar üzerinde yineleme yapmak zorundaysanız (çünkü vektörleştirilmiş bir karşılık yoksa), iterrows() yerine itertuples() kullanın. Her satırı Pandas Series yerine adlandırılmış demet olarak döndürür ve Series oluşturma ek yükünü ortadan kaldırır. Bu sayede genellikle iterrows'dan 5-10 kat daha hızlıdır. Değerlere öznitelik gösterimiyle erişin: row.column_name. Sütun adlarında boşluk varsa bunu kullanmaktan kaçının; bu adlar geçerli öznitelik adları değildir.

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')

Vektörleştirme Deseni Denetim Listesi

Bir döngü yazmadan önce şu soruları sorun:

  • İşlem tek bir sütunda öğe bazında mı uygulanıyor? → Bir sütun aritmetik ifadesi veya NumPy evrensel işlevi kullanın.
  • Koşullu mantık içeriyor mu? → 2 koşul için np.where, 3 veya daha fazla koşul için np.select kullanın.
  • Değerleri aralıklara mı ayırıyor? → pd.cut veya pd.qcut kullanın.
  • Dize işlemleri mi uyguluyor? → .str erişicisini kullanın.
  • Gruplar içinde toplulaştırma mı yapıyor? → groupby().agg() veya groupby().transform() kullanın.
Yukarıdakilerin hiçbiri uygun değilse yalnızca apply() veya itertuples() yöntemlerine başvurun.

Gerçek Hızlanma Örneği: Fiyat Hesaplama

Aşağıda, sipariş miktarına göre kademeli indirim uygulayan yaygın bir ticari hesaplamanın yeniden düzenleme öncesi ve sonrası tam örneği yer alır. Döngü sürümü okunabilirdir ancak büyük DataFrame nesneleri için kabul edilemeyecek kadar yavaştır. np.select kullanan vektörleştirilmiş sürüm aynı sonucu sürenin onda birinde elde eder.

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!')

Hızlı Kontrol

Bu derste öğrendiğiniz vektörleştirme konusunu ne kadar anladığınızı sınayın.

Ders Özeti

Bu derste şunları öğrendiniz: iterrows, vektörleştirilmiş işlemlerden 100-1000 kat daha yavaştır; np.where ve np.select koşullu döngülerin yerini alır; .str erişicisi dize işlemlerini vektörleştirir ve groupby().transform() elle grup yinelemesinin yerini alır. Yineleme yapmak zorundaysanız 5-10 kat iyileştirme için iterrows yerine itertuples kullanın. Sırada, sayısal türleri küçültmeyi ve belleği %70'e kadar azaltmak için Categorical kullanmayı ele alacağımız verimli veri türleri var.

Sıkça Sorulan Sorular

“iterrows ve Python Döngülerinden Kaçınma” dersi ücretsiz mi?

Evet — “iterrows ve Python Döngülerinden Kaçınma” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Pandas & NumPy Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Pandas & NumPy Academy kursu toplamda 4 dersten oluşur.

“iterrows ve Python Döngülerinden Kaçınma” dersinde ne öğreneceğim?

10-100 kat hızlanma elde etmek için satır satır döngüleri vektörleştirilmiş sütun işlemleri, np.where ve pd.cut ile değiştirin. Pandas & NumPy Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

Pandas & NumPy Academy öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te Pandas & NumPy Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 2. dersidir.

“iterrows ve Python Döngülerinden Kaçınma” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu Pandas & NumPy Academy dersinde kod yazıp çalıştırabilir miyim?

Evet. Her Pandas & NumPy Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. timeit ve memory_profiler ile Profilleme
  2. iterrows ve Python Döngülerinden Kaçınma
  3. Bellek Azaltma için Verimli Veri Türleri
  4. Büyük Dosyaları Parçalı Okuma
← Pandas & NumPy Academy Sayfasına Dön