İç içe kayıtlar ve küçük veri işleme

Bir ürünün ad, fiyat, stok bilgilerini sözlükte tutabildiğimizi gördük. Birden fazla ürün veya öğrenci kaydı olduğunda bu sözlükleri bir liste içinde saklayabiliriz.

Bu hafta ana hedef yeni bir Python yapısı öğrenmek değil; bildiğimiz liste, sözlük, koşul, döngü ve fonksiyonları birlikte kullanarak küçük veri kümelerini işlemek olacak. Filtreleme, özetleme ve basit gruplama kalıplarına odaklanacağız.

Bu hafta neleri yapabilmelisiniz?

Bölümün sonunda:

  • liste içinde sözlüklerden oluşan küçük kayıt yapısını okuyabilmeli,
  • bir kaydın alanlarına anlamlı anahtarlarla erişebilmeli,
  • belirli koşulu sağlayan kayıtları filtreleyebilmeli,
  • kayıtlardan toplam, ortalama ve sayı gibi özetler çıkarabilmeli,
  • belirli alana göre basit gruplama yapabilmeli,
  • eksik veya beklenmeyen alanlarda get() kullanmanın ne zaman uygun olduğunu açıklayabilmeli,
  • veri işleme kodunu küçük fonksiyonlara ayırabilmeli,
  • verilen küçük veri kümesinde beklenen sonucu elle hesaplayıp kodla karşılaştırabilmelisiniz.

Liste içinde sözlükler

Bir öğrenci kaydı:

ogrenci = {
    "ad": "Deniz",
    "bolum": "Bilgisayar",
    "puan": 78
}

Birden fazla öğrenci:

ogrenciler = [
    {"ad": "Deniz", "bolum": "Bilgisayar", "puan": 78},
    {"ad": "Ayşe", "bolum": "Siber", "puan": 92},
    {"ad": "Mert", "bolum": "Bilgisayar", "puan": 55}
]

Burada:

  • dış yapı bir liste,
  • her eleman bir sözlük,
  • sözlük içindeki "ad", "bolum" ve "puan" alanları kaydın özellikleridir.

İlk öğrencinin puanı:

print(ogrenciler[0]["puan"])

Önce listenin 0. elemanına, sonra o sözlüğün "puan" alanına erişilir.

Bir öğrenci listesindeki sözlük kayıtlarından indeks ve anahtar kullanarak iç içe veriye erişimi gösteren şema.

Kayıtlar üzerinde gezinmek

for ogrenci in ogrenciler:
    print(ogrenci["ad"], ogrenci["puan"])

Her yinelemede ogrenci değişkeni bir sözlüğü gösterir.

Bu yapı gerçek veri işleme kodlarında çok sık görülür:

kayıt listesi
    ↓
her kaydı sırayla al
    ↓
alanlarını oku
    ↓
koşula göre işle

Tahmin et — hangi kayıtlar yazılır?

Aşağıdaki kodu çalıştırmadan önce çıktıyı tahmin edin:

Bu kod stoku tükenen ürünleri filtreleyerek yazdırır.

Filtreleme: koşulu sağlayan kayıtları seçmek

Geçen hafta liste elemanlarından yeni liste oluşturmuştuk. Aynı kalıbı kayıtlarla kullanabiliriz:

ogrenciler = [
    {"ad": "Deniz", "puan": 78},
    {"ad": "Ayşe", "puan": 92},
    {"ad": "Mert", "puan": 55}
]

gecenler = []

for ogrenci in ogrenciler:
    if ogrenci["puan"] >= 60:
        gecenler.append(ogrenci)

print(gecenler)

Yeni liste yalnızca koşulu sağlayan kayıtları içerir.

Liste içindeki sözlük kayıtlarının bir koşula göre filtrelenip yeni bir kayıt listesine aktarılmasını gösteren şema.

Alıştırma — düşük stok kayıtlarını seçin

Stoku 5 veya daha az olan ürünleri dusuk_stok listesine ekleyin.

Beklenen listede Defter ve Silgi kayıtları bulunmalıdır.

if urun["stok"] <= 5: koşulu içinde dusuk_stok.append(urun) kullanabilirsiniz.

urunler = [
    {"ad": "Kalem", "stok": 12},
    {"ad": "Defter", "stok": 3},
    {"ad": "Silgi", "stok": 5},
    {"ad": "Cetvel", "stok": 8}
]

dusuk_stok = []

for urun in urunler:
    if urun["stok"] <= 5:
        dusuk_stok.append(urun)

print(dusuk_stok)

Özetleme: toplam ve ortalama

Kayıtların belirli alanını biriktirebiliriz.

satislar = [
    {"urun": "Kalem", "tutar": 120},
    {"urun": "Defter", "tutar": 250},
    {"urun": "Silgi", "tutar": 80}
]

toplam = 0

for satis in satislar:
    toplam = toplam + satis["tutar"]

print(toplam)

Sonuç 450 olur.

Ortalama:

ortalama = toplam / len(satislar)

Yine boş liste uç durumunu unutmamak gerekir.

Fonksiyonla özetleme

Veri işleme mantığını fonksiyona taşıyalım:

def puan_ortalamasi(ogrenciler):
    if len(ogrenciler) == 0:
        return 0

    toplam = 0

    for ogrenci in ogrenciler:
        toplam = toplam + ogrenci["puan"]

    return toplam / len(ogrenciler)

Bu fonksiyonun sözleşmesi daha açıktır:

Girdi:
- puan alanı olan öğrenci sözlüklerinin listesi

Çıktı:
- liste boşsa 0
- değilse puanların ortalaması

Alıştırma — toplam stok fonksiyonu

toplam_stok(urunler) fonksiyonunu tamamlayın.

Beklenen sonuç 20dir.

Döngü içinde toplam = toplam + urun["stok"] yazabilirsiniz.

def toplam_stok(urunler):
    toplam = 0

    for urun in urunler:
        toplam = toplam + urun["stok"]

    return toplam

urunler = [
    {"ad": "Kalem", "stok": 12},
    {"ad": "Defter", "stok": 3},
    {"ad": "Silgi", "stok": 5}
]

print(toplam_stok(urunler))

Basit gruplama

Verileri bir alana göre gruplamak için sözlük kullanabiliriz.

Örneğin bölüm başına öğrenci sayısı:

ogrenciler = [
    {"ad": "Deniz", "bolum": "Bilgisayar"},
    {"ad": "Ayşe", "bolum": "Siber"},
    {"ad": "Mert", "bolum": "Bilgisayar"},
    {"ad": "Ece", "bolum": "Siber"},
    {"ad": "Can", "bolum": "Bilgisayar"}
]

bolum_sayilari = {}

for ogrenci in ogrenciler:
    bolum = ogrenci["bolum"]
    bolum_sayilari[bolum] = bolum_sayilari.get(bolum, 0) + 1

print(bolum_sayilari)

Beklenen:

{'Bilgisayar': 3, 'Siber': 2}

Bu kalıp geçen haftaki frekans sayımının kayıt verisine uygulanmış hâlidir.

Gruplara toplam değer eklemek

Yalnızca kayıt sayısını değil, toplamları da gruplayabiliriz.

satislar = [
    {"kategori": "Kırtasiye", "tutar": 120},
    {"kategori": "İçecek", "tutar": 50},
    {"kategori": "Kırtasiye", "tutar": 80}
]

kategori_toplamlari = {}

for satis in satislar:
    kategori = satis["kategori"]
    tutar = satis["tutar"]
    kategori_toplamlari[kategori] = kategori_toplamlari.get(kategori, 0) + tutar

print(kategori_toplamlari)

Sonuç:

{'Kırtasiye': 200, 'İçecek': 50}

get() ile eksik alan düşüncesi

Bir veri kaydında alanın bulunmaması iki farklı anlam taşıyabilir:

urun = {"ad": "Kalem"}

"stok" alanı yoksa:

stok = urun.get("stok", 0)

yazabiliriz. Fakat bu ancak eksik stok bilgisini sıfır kabul etmek problem açısından doğruysa uygundur.

Başka bir problemde eksik alan veri kalitesi hatası olabilir ve sessizce 0 vermek yanlış sonucu gizleyebilir.

Important

get() teknik olarak hatayı engelleyebilir; fakat doğru varsayılan değeri problem kuralı belirler. “Program hata vermesin” tek başına doğru veri işleme değildir.

İç içe yapıyı izlemek

İç içe veri yapılarında bir ifadeyi soldan sağa çözmek faydalıdır:

ogrenciler[1]["puan"]

Adımlar:

  1. ogrenciler[1] → ikinci öğrenci sözlüğü
  2. ["puan"] → o sözlükteki puan değeri

Benzer şekilde:

satislar[0]["kategori"]

önce ilk kayıt, sonra "kategori" alanıdır.

Bu yaklaşım karmaşık ifadeleri “tek seferde anlamaya” çalışmaktan daha güvenlidir.

Değiştir — rapora yeni alan ekleyin

Aşağıdaki kayıtların her birine gecti alanı ekleyin. Puan 60 veya üzeriyse True, değilse False olsun.

Kodu çalıştırmadan önce her kaydın yeni hâlini tahmin edin.

Bu örnek mevcut sözlükleri yerinde değiştirir. Eğer orijinal veri korunmalıysa önce kopyalama veya yeni kayıt üretme gibi farklı tasarımlar gerekir.

Üret — bölüm bazında puan özeti

Aşağıdaki veri kümesi için bolum_puan_ozeti(ogrenciler) fonksiyonunu yazın:

ogrenciler = [
    {"ad": "Deniz", "bolum": "Bilgisayar", "puan": 80},
    {"ad": "Ayşe", "bolum": "Siber", "puan": 90},
    {"ad": "Mert", "bolum": "Bilgisayar", "puan": 60},
    {"ad": "Ece", "bolum": "Siber", "puan": 70}
]

Fonksiyon her bölüm için toplam puanı sözlükte toplasın.

Beklenen:

{'Bilgisayar': 140, 'Siber': 160}

Başlangıç:

Döngü içinde şu üç adımı düşünün: bolum = ..., puan = ..., toplamlar[bolum] = toplamlar.get(bolum, 0) + puan.

def bolum_puan_ozeti(ogrenciler):
    toplamlar = {}

    for ogrenci in ogrenciler:
        bolum = ogrenci["bolum"]
        puan = ogrenci["puan"]
        toplamlar[bolum] = toplamlar.get(bolum, 0) + puan

    return toplamlar

ogrenciler = [
    {"ad": "Deniz", "bolum": "Bilgisayar", "puan": 80},
    {"ad": "Ayşe", "bolum": "Siber", "puan": 90},
    {"ad": "Mert", "bolum": "Bilgisayar", "puan": 60},
    {"ad": "Ece", "bolum": "Siber", "puan": 70}
]

print(bolum_puan_ozeti(ogrenciler))

Veri işleme akışını parçalamak

Küçük veri problemlerini şu adımlarla düşünmek yararlıdır:

veriyi tanı
    ↓
hangi kayıtlar gerekli?
    ↓
hangi alanlar kullanılacak?
    ↓
filtrele / say / biriktir / grupla
    ↓
sonucu açık bir yapıda döndür

Bir fonksiyon her şeyi aynı anda yapmak zorunda değildir. Örneğin:

def gecen_ogrenciler(ogrenciler):
    sonuc = []

    for ogrenci in ogrenciler:
        if ogrenci["puan"] >= 60:
            sonuc.append(ogrenci)

    return sonuc

ve

def puan_ortalamasi(ogrenciler):
    ...

ayrı sorumluluklara sahip olabilir.

Bölüm özeti

Bu hafta mevcut Python yapılarını birlikte kullanarak küçük veri işleme problemlerine uyguladık.

  • Bir kayıt sözlükle, kayıt kümesi listeyle temsil edilebilir.
  • liste[indeks]["alan"] önce kaydı, sonra alanı seçer.
  • Filtreleme, koşulu sağlayan kayıtları yeni listeye ekleme kalıbıdır.
  • Özetleme, alan değerlerini sayma veya biriktirme işlemidir.
  • Gruplama için sözlük anahtarları grup adlarını temsil edebilir.
  • get(grup, 0) grup toplamı veya sayacı oluştururken kullanışlıdır.
  • Eksik alan için varsayılan değer kullanmanın doğru olup olmadığı problem kurallarına bağlıdır.
  • Veri işleme kodu küçük ve tek amaçlı fonksiyonlara ayrıldığında daha kolay doğrulanır.

Kendinizi kontrol edin

  1. Liste içinde sözlük yapısının avantajı nedir?
  2. ogrenciler[2]["puan"] ifadesini iki adımda açıklayın.
  3. Filtreleme kalıbı ne yapar?
  4. Bir kayıt listesindeki toplam tutarı hesaplarken hangi biriktirici kalıbı kullanılır?
  5. Bölüm başına öğrenci sayısı için sözlük neden uygundur?
  6. Eksik alanı 0 kabul etmek hangi durumda yanlış olabilir?
  7. Mevcut kaydı değiştirerek yeni alan eklemek ile yeni kayıt üretmek arasında ne fark vardır?
  8. Veri işleme fonksiyonlarını küçük parçalara ayırmanın yararı nedir?

Bir sonraki bölümde bu tür kayıtları program dışından almak ve dışarıya yazmak için dosyalar ve CSV biçimiyle çalışacağız.

Back to top