---
title: 'Gruplama ve Toplulaştırma'
source: 'https://academia.sh/tr/kurslar/python-ile-analiz/gruplama-ve-toplulastirma'
course: 'Python ile Veri Analizi'
language: tr
updated: '2026-08-17T18:08:43+00:00'
license: 'CC BY-SA 4.0'
---

# Gruplama ve Toplulaştırma

Böl, uygula ve birleştir adımları tek çağrıya sığıyor ve o çağrı iki kararı birden taşıyor: grup anahtarı boş olan 160 satır varsayılan gruplamada hiçbir grupta görünmez ve beş satırlık özetin toplamı 63.060,63 m³ yerine 60.025,56 m³ çıkar, yani kümenin yüzde 4,81'i hiçbir uyarı üretmeden düşer. Eksik anahtar korunduğunda özet 6 satır olur ve düşen kısım 3.035,07 m³ olarak görünür hale gelir. İkinci karar toplulaştırmanın paydasıdır: kuzey grubu 878 satır taşır ama endeks sütununda 831 dolu değer vardır ve ortalama, paydaya göre 126.247,9 ya da 119.489,8 çıkar. Ölçüt başına ayrı döngü 15.995 anahtar araması tutarken tek bölme 3.199 aramayla beş ölçütü besler.

Süzgeç satırları seçer, ama rapor tek tek satır istemez; kırılıma göre özet ister. "Bölge başına
ortalama endeks" sorusu üç adımlık bir iştir: küme anahtara göre **bölünür**, her parçaya bir hesap
**uygulanır**, sonuçlar tek tabloda **birleştirilir**. Veri Toplama ve Hazırlama kursunun gruplama
dersi bu üç adımı elle yazılan döngülerle yürütmüş ve gruplama kararının çıkan satır sayısını
belirlediğini ölçmüştü; oradaki hesap bu dersin girdisidir ve tekrarlanmaz.

Burada değişen şey, üç adımın tek bir çağrıya sığmasıdır. O çağrı iki ayrı kararı birden taşır ve
ikisi de yazılmaz: grup anahtarı boş olan satır hangi gruba girer ve toplulaştırma hesabı neyi
payda alır. Bu dersin ölçüsü bu iki kararın kaç satırı ve kaç metre küpü oynattığıdır.

- **VC18. Böl–uygula–birleştir**, gruplamanın üç adımıdır. Bölme anahtar başına bir kova kurar,
  uygulama her kovada bir hesap yapar, birleştirme kova başına bir satır çıkarır. Çıkan satır
  sayısı **anahtarın farklı değer sayısıdır**, kümenin satır sayısı değil.
- **VC19.** Grup anahtarı eksik olan satır bir kovaya ait değildir. Varsayılan davranış onu
  **düşürmektir**; eksik değeri kendi kovasında toplamak da meşru bir karardır ve iki karar arasında
  fark bir satır sayısı ve bir toplamdır.
- **VC20. Toplulaştırmanın paydası** ayrı bir karardır. Ortalama, toplulaştırılan sütunun **dolu**
  değerlerini sayarak da, grubun **bütün** satırlarını sayarak da hesaplanabilir. İki payda iki
  ortalama verir ve rapordaki `n` sütunu hangisini yazdığını söylemek zorundadır.
- **VC21.** Bölme adımı bir kez yapılırsa aynı kovalar birçok ölçüt tarafından paylaşılır. Kazancın
  ölçüsü **anahtar araması sayısıdır**, değer okuması sayısı değil.

## Anahtar Bulunmayan Satır

```python
# kume.py — MODELDIR: bir onceki dersin uzun bicimli okuma tablosu ayni tohumla
# yeniden uretilir. Kume kurgudur; uretecin ayrintisi konunun ilk dersindedir.
import math

M32 = 0xFFFFFFFF
TOHUM, DONEM = 20260218, ["2026-01", "2026-02", "2026-03"]
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]

def uretec(tohum: int):
    s = ((tohum ^ (tohum >> 16)) * 2246822507) & M32
    s = ((s ^ (s >> 13)) * 3266489909) & M32
    s ^= s >> 16
    def sonraki() -> float:
        nonlocal s
        s = (s * 1664525 + 1013904223) & M32
        return s / 4294967296
    return sonraki

def ayrik(u: float, agirlik: list[float]) -> int:
    t = 0.0
    for i, p in enumerate(agirlik):
        t += p
        if u < t:
            return i
    return len(agirlik) - 1

abone, elenen = [], []
for i in range(1400):
    r = uretec(TOHUM + i)
    ad, _, taban = BOLGE[ayrik(r(), [b[1] for b in BOLGE])]
    r(); r()  # hane ve memnuniyet cekilisleri bu derste kullanilmiyor
    (elenen if r() < 0.046 else abone).append(
        {"abone_no": 10001 + i, "bolge": ad, "taban": taban})

gecerli = {k["abone_no"] for k in abone}
cift: dict[tuple[int, str], float] = {}
for k in abone + elenen:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] in gecerli:
            cift.setdefault((k["abone_no"], DONEM[d]), t)
        r()
UZUN = [{"abone_no": a, "donem": d, "tuketim_m3": t} for (a, d), t in cift.items()]

# Grup anahtari abonenin bolgesidir; bir kisim abonenin adres kaydi eslesmedigi
# icin bolgesi bostur. Endeks sutunu bir onceki dersteki gibi eksik tasir.
EKSIK = None

def bolge_hucresi(no: int, ad: str):
    return EKSIK if uretec(TOHUM + 61000 + no)() < 0.048 else ad

bolge_of = {k["abone_no"]: bolge_hucresi(k["abone_no"], k["bolge"]) for k in abone}
kumul: dict[int, float] = {}
kayit = []
for o in UZUN:
    no, t = o["abone_no"], o["tuketim_m3"]
    kumul[no] = kumul.get(no, 0.0) + t
    u = uretec(TOHUM + 9100 + no * 4 + DONEM.index(o["donem"]))()
    endeks = EKSIK if u < 0.055 else 100000 + (no - 10000) * 37 + int(kumul[no])
    kayit.append({"abone_no": no, "donem": o["donem"], "tuketim_m3": t,
                  "endeks": endeks, "bolge": bolge_of[no]})

print(f"{len(kayit)} satir; grup anahtari bos olan "
      f"{sum(1 for k in kayit if k['bolge'] is EKSIK)} satir, toplulastirilacak "
      f"sutunu bos olan {sum(1 for k in kayit if k['endeks'] is EKSIK)} satir")
print(f"kumenin gercek toplami {round(sum(k['tuketim_m3'] for k in kayit), 2)} m3")
```

```
3199 satir; grup anahtari bos olan 160 satir, toplulastirilacak sutunu bos olan 191 satir
kumenin gercek toplami 63060.63 m3
```

İki eksiklik aynı kümede duruyor ve birbirinden bağımsız. 160 satırın **grup anahtarı** boştur:
abonenin adres kaydı bir bölgeye eşleşmemiştir. 191 satırın **toplulaştırılacak sütunu** boştur:
sayaç okunamamış, endeks kaydedilmemiştir. İki eksikliğin ikisi de aynı gruplama çağrısının içinden
geçer ve çağrı her birine ayrı davranır.

Kümenin gerçek toplamı 63.060,63 m³'tür ve bu sayı bu dersin denetim çıpasıdır. Bir özet tablonun
toplamı bununla karşılaştırılabildiği sürece gruplamanın ne kaybettiği okunabilir; karşılaştırılmadığı
sürece özet kendi içinde tutarlı görünür ve hiçbir şey söylemez.

## Böl, Uygula, Birleştir

```python
# bol_uygula_birlestir.py — gruplama uc adimdir: bol, uygula, birlestir.
# Tek cagriya sigar ve iki karari birden tasir.
def bol(kayitlar, anahtar: str, eksigi_dusur=True):
    """Bol adimi: satirlar anahtara gore kovalara dagitilir."""
    kova, dusen = {}, 0
    for k in kayitlar:
        if k[anahtar] is EKSIK and eksigi_dusur:
            dusen += 1
            continue
        kova.setdefault(k[anahtar], []).append(k)
    return kova, dusen

def uygula(kova, sutun: str):
    """Uygula adimi: her kovada sayim, toplam ve iki ayri paydayla ortalama."""
    cikti = []
    for ad, satirlar in kova.items():
        dolu = [k[sutun] for k in satirlar if k[sutun] is not EKSIK]
        cikti.append({
            "grup": "(eksik)" if ad is EKSIK else ad,
            "satir": len(satirlar), "dolu": len(dolu),
            "toplam_m3": round(sum(k["tuketim_m3"] for k in satirlar), 2),
            "ort_dolu": round(sum(dolu) / len(dolu), 1) if dolu else 0.0,
            "ort_satir": round(sum(dolu) / len(satirlar), 1)})
    return sorted(cikti, key=lambda c: c["grup"])

EN = [12, 8, 8, 12, 12, 12]
y = lambda h: "".join(str(v).rjust(EN[k]) if k else str(v).ljust(EN[0])
                      for k, v in enumerate(h))
kova, dusen = bol(kayit, "bolge")
ozet = uygula(kova, "endeks")
print(y(["grup", "satir", "dolu", "toplam m3", "ort/dolu", "ort/satir"]))
for c in ozet:
    print(y([c["grup"], c["satir"], c["dolu"], c["toplam_m3"], c["ort_dolu"], c["ort_satir"]]))
print(y(["birlesim", sum(c["satir"] for c in ozet), sum(c["dolu"] for c in ozet),
         round(sum(c["toplam_m3"] for c in ozet), 2), "", ""]))
print(f"\nvarsayilan gruplama {len(ozet)} satirlik ozet uretti ve {dusen} satiri "
      f"hicbir grupta gostermedi")
```

```
grup           satir    dolu   toplam m3    ort/dolu   ort/satir
bati             444     415     6123.43    126006.5    117776.3
dogu             533     508    13203.17    124854.4    118998.2
guney            614     574    10153.66    125303.5    117140.4
kuzey            878     831     17749.3    126247.9    119489.8
merkez           570     533     12796.0    125262.2    117131.2
birlesim        3039    2861    60025.56                        

varsayilan gruplama 5 satirlik ozet uretti ve 160 satiri hicbir grupta gostermedi
```

Beş satırlık bir özet çıktı ve tek başına bakıldığında kusursuz görünüyor. Bölge adları tam, sayımlar
makul, ortalamalar birbirine yakın. Kusur yalnız birleşim satırında görünür: 3.039 satır sayılmıştır,
oysa küme 3.199 satırdır; toplam 60.025,56 m³'tür, oysa küme 63.060,63 m³'tür.

Aradaki 160 satır hiçbir yerde raporlanmamıştır. Bir hata mesajı, bir uyarı, hatta boş bir satır bile
yoktur; o satırlar için bir kova açılmadığı için tabloda görünecek bir yer de oluşmamıştır. Bu, bir
önceki derste ölçülen sessiz kayıptan yapıca farklıdır: orada süzgeç bir koşula göre karar veriyordu,
burada karar veren şey **kovanın var olmamasıdır**.

Tablonun son iki sütunu ikinci kararı gösteriyor. Kuzey grubunda 878 satır vardır ama endeks
sütununda 831 dolu değer vardır. Ortalama, dolu değerleri sayarsa 126.247,9, grubun bütün
satırlarını sayarsa 119.489,8 çıkar. İki sayı da bir ortalamadır ve aralarında 6.758,1 fark vardır.

## İki Karar, İki Sayı

```python
# karar.py — iki karar ayri ayri olculur: grup anahtarindaki eksik ve
# toplulastirmanin paydasi.
kova2, dusen2 = bol(kayit, "bolge", eksigi_dusur=False)
ozet2 = uygula(kova2, "endeks")
eks = next(c for c in ozet2 if c["grup"] == "(eksik)")
t1 = round(sum(c["toplam_m3"] for c in ozet), 2)
t2 = round(sum(c["toplam_m3"] for c in ozet2), 2)
print(f"eksik anahtar korunursa ozet {len(ozet)} yerine {len(ozet2)} satir olur; "
      f"kovalardaki satir {sum(c['satir'] for c in ozet2)}, toplam {t2} m3")
print(f"(eksik) grubu {eks['satir']} satir ve {eks['toplam_m3']} m3 tasir; varsayilan "
      f"gruplama bunu dusurur ve toplam {t1} m3 kalir")
print(f"kaybolan pay: {round(100 * (t2 - t1) / t2, 2)} yuzde, hicbir uyari uretilmeden")

kuzey = next(c for c in ozet if c["grup"] == "kuzey")
print(f"\nkuzey grubunda iki ayri sayim var: {kuzey['satir']} satir ve {kuzey['dolu']} "
      f"dolu endeks; ortalama {kuzey['ort_dolu']} ya da {kuzey['ort_satir']}")
print(f"ayni satirda 'n' yazan bir rapor hangisini yazdigini soylemek zorundadir")

OLCUT = ["sayim", "toplam", "ortalama", "en buyuk", "en kucuk"]
print(f"\ngecis : olcut basina ayri dongu {len(OLCUT) * len(kayit)} anahtar aramasi, "
      f"tek bolme {len(kayit)} anahtar aramasi ve {len(OLCUT) * len(kayit)} deger okumasi")
print(f"kod   : olcut basina ayri dongu {len(OLCUT)} blok, tek bolmeye "
      f"{len(OLCUT)} uygulama 1 cagri")
```

```
eksik anahtar korunursa ozet 5 yerine 6 satir olur; kovalardaki satir 3199, toplam 63060.63 m3
(eksik) grubu 160 satir ve 3035.07 m3 tasir; varsayilan gruplama bunu dusurur ve toplam 60025.56 m3 kalir
kaybolan pay: 4.81 yuzde, hicbir uyari uretilmeden

kuzey grubunda iki ayri sayim var: 878 satir ve 831 dolu endeks; ortalama 126247.9 ya da 119489.8
ayni satirda 'n' yazan bir rapor hangisini yazdigini soylemek zorundadir

gecis : olcut basina ayri dongu 15995 anahtar aramasi, tek bolme 3199 anahtar aramasi ve 15995 deger okumasi
kod   : olcut basina ayri dongu 5 blok, tek bolmeye 5 uygulama 1 cagri
```

Tek bir seçeneğin değişmesi özeti beş satırdan altı satıra çıkarıyor ve altıncı satır düşen kısmın
tamamını taşıyor: 160 satır, 3.035,07 m³, kümenin yüzde 4,81'i. Altı satırlık özetin toplamı kümenin
gerçek toplamına eşittir ve bu eşitlik, bir gruplamanın doğrulanabilmesi için gereken tek denetimdir.

İki kararın da savunulabilir tarafı vardır. Bölgesi bilinmeyen 160 satırı bölge kırılımına sokmak
anlamsızdır, çünkü hangi bölgeye ait olduğu bilinmez. Ama onları tabloya hiç yazmamak, bölge
toplamlarının küme toplamını vermemesine ve bunun görünmemesine yol açar. Aradaki fark bir tercih
değil, bir **raporlama borcudur**: düşen satır sayılıp yazıldığı sürece hangi karar verilirse
verilsin rapor okunabilir kalır.

Paydanın kararı da aynı yapıdadır. Kuzey grubunun ortalama endeksi, ölçülmüş 831 değerin ortalaması
olarak 126.247,9'dur; ölçülememiş 47 satırı da paya katan hesapta 119.489,8'e iner. İkincisi
"okunamayan sayaçların endeksi sıfırdır" demekle aynı şeydir ve bu bir varsayımdır. Ortalamanın
yanında `n` yazılmadığında iki sayı birbirinden ayırt edilemez.

Kazanç tarafı son iki satırdadır. Beş ölçüt için beş ayrı döngü yazmak 15.995 anahtar araması tutar,
çünkü her ölçüt kümeyi baştan tarar ve kovaları yeniden kurar. Böl–uygula–birleştir bölme adımını
bir kez yapar: 3.199 anahtar araması, ardından beş ölçüt aynı kovalar üzerinde 15.995 değer okumasıyla
hesaplanır. Anahtar araması beşte bire iner, kod beş bloktan tek çağrıya düşer ve tam da bu kısalma
iki kararı görünmez kılar.

## Özetin Kendisi de Bir Çerçevedir

```python
# pay.py — ozetin kendisi de bir cercevedir ve etiket dizini grup anahtaridir.
# Pay hesabi hangi toplami payda aldigina gore iki ayri tablo verir.
P = [12, 12, 12, 12]
p = lambda h: "".join(str(v).rjust(P[k]) if k else str(v).ljust(P[0])
                      for k, v in enumerate(h))
print(p(["grup", "toplam m3", "pay/ozet", "pay/kume"]))
for c in ozet:
    print(p([c["grup"], c["toplam_m3"], round(100 * c["toplam_m3"] / t1, 2),
             round(100 * c["toplam_m3"] / t2, 2)]))
print(p(["birlesim", t1, round(sum(100 * c["toplam_m3"] / t1 for c in ozet), 2),
         round(sum(100 * c["toplam_m3"] / t2 for c in ozet), 2)]))
print(f"\nozet toplamini payda alan tablo yuzde 100 ile kapanir ve dusen {dusen} "
      f"satiri gizler; kume toplamini payda alan tablo yuzde "
      f"{round(100 - sum(100 * c['toplam_m3'] / t2 for c in ozet), 2)} acik birakir")
```

```
grup           toplam m3    pay/ozet    pay/kume
bati             6123.43        10.2        9.71
dogu            13203.17        22.0       20.94
guney           10153.66       16.92        16.1
kuzey            17749.3       29.57       28.15
merkez           12796.0       21.32       20.29
birlesim        60025.56       100.0       95.19

ozet toplamini payda alan tablo yuzde 100 ile kapanir ve dusen 160 satiri gizler; kume toplamini payda alan tablo yuzde 4.81 acik birakir
```

Toplulaştırmanın çıktısı yeni bir çerçevedir ve etiket dizini grup anahtarıdır. Bu, konunun ilk
dersindeki kuralı gruplamanın sonucuna da uygular: bir sonraki işlem bu dizin üzerinden hizalanır ve
dizinde bulunmayan bir grup sessizce eksik olur. Pay hesabı bunun en sık görülen biçimidir, çünkü
payda seçimi tam da bir dizin seçimidir.

İki pay sütunu aynı beş sayıdan çıkıyor ve farkları yalnız paydada. Özet toplamını payda alan sütun
yüzde 100 ile kapanır; tabloya bakan biri hiçbir eksiklik göremez, çünkü bir yüzde tablosunun 100
ile kapanması doğruluğun işareti sayılır. Küme toplamını payda alan sütun ise yüzde 95,19'da kapanır
ve kalan **yüzde 4,81** tablonun kendisinde bir soru olarak durur.

İkinci tablonun eksik kapanması bir kusur değil, bir bulgudur. Yüzde 100 ile kapanan tablo, düşen 160
satırın varlığını tabloyu bozmadan gizleyebildiği için daha tehlikelidir: kapanma denetimi geçmiş,
denetimin ölçtüğü şey ise kaybın olmaması değil, payların kendi içinde tutarlı olmasıdır.

## Özet

- Böl–uygula–birleştir üç adımdır ve çıkan satır sayısı anahtarın farklı değer sayısıdır; bölme
  adımını bir kez yapmak anahtar aramasını 15.995'ten 3.199'a indirir.
- Grup anahtarı boş olan 160 satır varsayılan gruplamada hiçbir kovaya girmez ve tabloda görünecek
  bir yeri de oluşmaz; özet 3.039 satır sayar, küme 3.199 satırdır.
- Düşen kısım 3.035,07 m³'tür, yani kümenin yüzde 4,81'i; eksik anahtar korunduğunda özet 6 satır
  olur ve toplamı kümenin gerçek toplamına eşitlenir.
- Toplulaştırmanın paydası ikinci karardır: kuzey grubu 878 satır ve 831 dolu endeks taşır, ortalama
  paydaya göre 126.247,9 ya da 119.489,8 çıkar.
- Bir özet tablonun tek zorunlu denetimi, grup toplamlarının küme toplamına eşitlenmesidir; eşitlik
  kurulmadığında özet kendi içinde tutarlı görünür ve düşen satırı bildirmez.

## Sonraki Adım

Gruplama tek bir tablonun içinde kalır. Analizin çoğu sorusu ise birden çok tablo ister: okuma
tablosunun yanına abone bilgisi, abone bilgisinin yanına saha ziyaretleri gelmelidir. Veri Toplama ve
Hazırlama kursunda bu iş elle yazılan bir eşleştirme döngüsüyle yapılmış ve satır hesabı kalem kalem
tutulmuştu. Bir veri çerçevesi arayüzünde aynı iş tek bir çağrıdır ve o çağrı bir birleştirme türü
seçer. Sonraki ders iç, dış ve çapraz birleştirmeyi aynı iki tabloya uygular ve her birinin kaç satır
ürettiğini, anahtarın tekil olmadığı yerde satırların nasıl çoğaldığını sayar.
