---
title: Yayılım
source: 'https://academia.sh/tr/kurslar/python-ile-analiz/yayilim'
course: 'Python ile Veri Analizi'
language: tr
updated: '2026-08-17T18:08:44+00:00'
license: 'CC BY-SA 4.0'
---

# Yayılım

Yayılım kuralı standart kitaplıkla modellenir ve sekiz biçim çifti üzerinde koşturulur: 4 çift doğru sonuç, 2 çift hata, 2 çift sessizce beklenmedik biçimde bir dizi üretir. Sessiz durumun bedeli sayılır: (1260, 1) ile (1, 1260) çarpımı 1.260 öğe yerine 1.587.600 öğe verir, ayrılan bayt 10.160'tan 12.700.880'e çıkar, öğelerin yalnız 1.260'ı doğrudur ve raporlanan kişi başı ortalama 36,938180 yerine 36,497564 m³ olur. İkinci sessiz durumda dönem tabanı 3 değer yerine 9 değer üretir ve düzeltilmiş taban toplamı 83,901904 m³ yerine 251,846368 m³ çıkar.

Önceki derste bütün işlemler bir dizi ile bir sayı arasında yapıldı ve biçim hiç değişmedi.
Gerçek hesaplarda iki dizi karşılaşır ve biçimleri çoğu zaman aynı olmaz: 3.780 hücrelik okuma
tablosunun yanında dönem başına bir taban (3 değer), abone başına bir hane sayısı (1.260 değer)
ve tarife basamağı başına bir birim fiyat (3 değer) durur. Bunları teker teker döngüyle
eşleştirmek yerine dizi arayüzü **yayılım** kuralını uygular: küçük biçim, büyük biçme uyacak
şekilde tekrarlanmış sayılır.

Kural iki satırda anlatılır ve tam olarak iki satır olduğu için tehlikelidir. Biçimler **sağdan
hizalanır**; hizalanan her boyutta ya iki sayı eşittir ya da biri 1'dir. Bu koşul sağlanırsa işlem
yapılır. Koşulun sağlanması işlemin **doğru** olduğu anlamına gelmez, yalnız **mümkün** olduğu
anlamına gelir. Bu dersin ölçtüğü şey aradaki farktır.

- **SH7.** Yayılım kuralı biçimlerin uyumunu denetler, işlemin anlamını denetlemez. Kural
  sağlandığında hesap yapılır ve hiçbir uyarı üretilmez.
- **SH8.** Uyumsuz bir biçim çifti iki sonuçtan birini verir: bir hata ya da beklenmedik
  büyüklükte bir dizi. Birincisi hesabı durdurur, ikincisi hesabı sürdürür ve öğe sayısını binlerce
  kat büyütebilir.

## Kuralı Yazmak

```python
# yayilim.py — MODELDIR: yayilim kurali standart kitaplikla yaziliyor. Kural:
# bicimler sagdan hizalanir; her boyutta ya iki sayi esittir ya da biri 1'dir.
# Kural saglanirsa islem yapilir. Kutuphane cagrilmiyor.
import math

def yayilim_bicimi(b1, b2):
    n = max(len(b1), len(b2))
    s1 = (1,) * (n - len(b1)) + tuple(b1)
    s2 = (1,) * (n - len(b2)) + tuple(b2)
    c = []
    for x, y2 in zip(s1, s2):
        if x == y2 or x == 1 or y2 == 1:
            c.append(max(x, y2))
        else:
            return None
    return tuple(c)

oge = lambda b: 0 if b is None else math.prod(b)
CIFT = [
    ("okuma x tek katsayi",        (1260, 3), (1,),        3780),
    ("okuma x donem tabani",       (1260, 3), (3,),        3780),
    ("okuma x abone hane sayisi",  (1260, 3), (1260, 1),   3780),
    ("okuma x abone (duz yazim)",  (1260, 3), (1260,),     3780),
    ("okuma x donem (iki boyut)",  (1260, 3), (1, 3),      3780),
    ("abone toplami x hane satiri", (1260, 1), (1, 1260),  1260),
    ("donem tabani x donem duzeltme", (3,),   (3, 1),      3),
    ("okuma x iki basamak",        (1260, 3), (2,),        3780),
]
gen = lambda w: lambda h: "".join(str(v).ljust(w[0]) if j == 0 else str(v).rjust(w[j])
                                  for j, v in enumerate(h))
y = gen([32, 12, 11, 13, 11, 11, 9])
print(y(["islem", "bicim 1", "bicim 2", "sonuc bicimi", "oge", "beklenen", "sonuc"]))
hata = sessiz = dogru = 0
for ad, b1, b2, bek in CIFT:
    c = yayilim_bicimi(b1, b2)
    if c is None:
        d, hata = "hata", hata + 1
    elif oge(c) != bek:
        d, sessiz = "sessiz", sessiz + 1
    else:
        d, dogru = "dogru", dogru + 1
    print(y([ad, str(b1), str(b2), str(c) if c else "-", oge(c), bek, d]))
print(f"\n{len(CIFT)} cift: {dogru} dogru, {hata} hata, {sessiz} sessizce beklenmedik bicim")
```

```
islem                                bicim 1    bicim 2 sonuc bicimi        oge   beklenen    sonuc
okuma x tek katsayi                (1260, 3)       (1,)    (1260, 3)       3780       3780    dogru
okuma x donem tabani               (1260, 3)       (3,)    (1260, 3)       3780       3780    dogru
okuma x abone hane sayisi          (1260, 3)  (1260, 1)    (1260, 3)       3780       3780    dogru
okuma x abone (duz yazim)          (1260, 3)    (1260,)            -          0       3780     hata
okuma x donem (iki boyut)          (1260, 3)     (1, 3)    (1260, 3)       3780       3780    dogru
abone toplami x hane satiri        (1260, 1)  (1, 1260) (1260, 1260)    1587600       1260   sessiz
donem tabani x donem duzeltme           (3,)     (3, 1)       (3, 3)          9          3   sessiz
okuma x iki basamak                (1260, 3)       (2,)            -          0       3780     hata

8 cift: 4 dogru, 2 hata, 2 sessizce beklenmedik bicim
```

İlk üç satır kuralın işe yaradığı yerlerdir ve kazanç gerçektir. Dönem başına taban çıkarmak elle
yazıldığında iki iç içe döngü ve bir dizin hesabı tutar; yayılımla tek işlemdir ve 3 değerlik
taban 1.260 kez tekrarlanmış gibi davranır — tekrarlanan kopya bellekte oluşturulmadan. Abone
başına hane sayısı da aynı şekilde, biçim (1260, 1) yazıldığı sürece, doğru yönde yayılır.

Dördüncü satır kuralın **koruduğu** yerdir. Abone başına hane sayısı düz bir dizi olarak,
yani (1260,) biçiminde yazılırsa sağdan hizalama son boyutları karşılaştırır: 3 ile 1.260. İkisi
de birbirine eşit değil ve hiçbiri 1 değil, dolayısıyla kural sağlanmaz ve işlem yapılmaz. Bu bir
kusur değil, kuralın tek gerçek güvencesidir: **yanlış eksende hizalama girişimi çoğu zaman
durdurulur.** Sekizinci satır da aynı türdendir; iki basamaklık bir katsayı dizisi üç dönemlik bir
tabloya yayılamaz.

Altıncı ve yedinci satırlar ise durdurulmaz. Kural sağlanır, işlem yapılır ve sonuç beklenenden
başka bir biçimdedir. Sekiz çiftin ikisi bu durumda ve ikisinin de ortak yanı şudur: yazan kişi
biçimlerden **birini** transpoze yazmıştır. Bir sonraki bölüm bunun bedelini sayıyor.

## Sessizce Üretilen Sonuç

```python
# sessiz.py — MODELDIR: sessizce uretilen sonucun bedeli. Abone basina toplam
# tuketim, abone basina hane sayisina bolunuyor. Hane sayisi kurgudur.
import sys
from array import array

def uretec(tohum):
    s = tohum & 0xFFFFFFFF
    def sonraki():
        nonlocal s
        s = (1664525 * s + 1013904223) & 0xFFFFFFFF
        return s / 4294967296
    return sonraki

ABONE, DONEM = 1260, 3
r = uretec(20260218)
HAM = [round(4 + r() * 56, 2) for _ in range(ABONE * DONEM)]
r2 = uretec(9110723)
p = [r2() for _ in range(ABONE * DONEM)]
BOS = set(sorted(range(len(p)), key=lambda j: p[j])[:581])
OKUMA = [0.0 if j in BOS else HAM[j] for j in range(ABONE * DONEM)]
r3 = uretec(31081977)
HANE = [1 + int(r3() * 5) for _ in range(ABONE)]
TOPLAM = [sum(OKUMA[i*DONEM:(i+1)*DONEM]) for i in range(ABONE)]

# Dogru yazim: (1260, 1) ile (1260, 1)
DOGRU = array("d", [TOPLAM[i] / HANE[i] for i in range(ABONE)])
# Sessiz yazim: (1260, 1) ile (1, 1260) -> (1260, 1260)
YANLIS = array("d", [TOPLAM[i] / HANE[j] for i in range(ABONE) for j in range(ABONE)])
kosegen = [YANLIS[i * ABONE + i] for i in range(ABONE)]
dogru_oge = sum(1 for i in range(ABONE) if abs(kosegen[i] - DOGRU[i]) < 1e-9)
z = gen([26, 18, 20, 12])
print(z(["olcu", "dogru yazim", "sessiz yazim", "oran"]))
print(z(["sonuc bicimi", "(1260, 1)", "(1260, 1260)", "-"]))
print(z(["oge sayisi", len(DOGRU), len(YANLIS), f"{len(YANLIS)//len(DOGRU)}x"]))
print(z(["ayrilan bayt", sys.getsizeof(DOGRU), sys.getsizeof(YANLIS),
         f"{sys.getsizeof(YANLIS)//sys.getsizeof(DOGRU)}x"]))
print(z(["kisi basi ortalama", f"{sum(DOGRU)/len(DOGRU):.6f}", f"{sum(YANLIS)/len(YANLIS):.6f}",
         "-"]))
print(f"\nsessiz dizinin {len(YANLIS)} ogesinin {dogru_oge}'i dogru (kosegen), "
      f"{len(YANLIS)-dogru_oge} ogesi bir abonenin tuketimini baska bir abonenin hanesine boluyor")
print(f"raporlanan kisi basi ortalama {sum(DOGRU)/len(DOGRU):.6f} yerine "
      f"{sum(YANLIS)/len(YANLIS):.6f} m3, fark {abs(sum(YANLIS)/len(YANLIS)-sum(DOGRU)/len(DOGRU)):.6f} m3")

# Ikinci sessiz durum: donem tabani (3,) ile mevsim duzeltmesi (3, 1).
DONEM_ORT = [sum(OKUMA[i*DONEM+d] for i in range(ABONE)) / ABONE for d in range(DONEM)]
DUZELTME = [0.98, 1.03, 1.10]   # kurgu mevsim duzeltmesi
d3 = [DONEM_ORT[d] * DUZELTME[d] for d in range(DONEM)]
s3 = [DONEM_ORT[d] * DUZELTME[e] for e in range(DONEM) for d in range(DONEM)]
print(f"\nikinci sessiz durum: donem tabani (3,) ile duzeltme (3, 1) carpiminda sonuc "
      f"{len(d3)} deger yerine {len(s3)} deger")
print(f"duzeltilmis taban toplami {sum(d3):.6f} m3 yerine {sum(s3):.6f} m3; "
      f"bicim buyudugu icin toplam {sum(s3)/sum(d3):.4f} katina cikti")
```

```
olcu                             dogru yazim        sessiz yazim        oran
sonuc bicimi                       (1260, 1)        (1260, 1260)           -
oge sayisi                              1260             1587600       1260x
ayrilan bayt                           10160            12700880       1250x
kisi basi ortalama                 36.938180           36.497564           -

sessiz dizinin 1587600 ogesinin 1260'i dogru (kosegen), 1586340 ogesi bir abonenin tuketimini baska bir abonenin hanesine boluyor
raporlanan kisi basi ortalama 36.938180 yerine 36.497564 m3, fark 0.440616 m3

ikinci sessiz durum: donem tabani (3,) ile duzeltme (3, 1) carpiminda sonuc 3 deger yerine 9 deger
duzeltilmis taban toplami 83.901904 m3 yerine 251.846368 m3; bicim buyudugu icin toplam 3.0017 katina cikti
```

Hesap şudur: her abonenin üç dönemlik toplam tüketimi, o abonenin hane sayısına bölünecek. Doğru
sonuç 1.260 değerdir. Hane sayısı dizisi satır olarak yazılınca, yani (1260, 1) yerine (1, 1260)
biçiminde, kural yine sağlanır — birinci boyutta 1.260 ile 1, ikinci boyutta 1 ile 1.260 karşılaşır
ve her ikisinde de taraflardan biri 1'dir. Sonuç **1.587.600 öğelik** bir dizidir ve içinde her
abonenin tüketimi her abonenin hane sayısına bölünmüş halde durur.

Bedelin üç ayrı ölçüsü var. Öğe sayısı 1.260 kat, ayrılan bayt 10.160'tan 12.700.880'e, yani 1.250
kat büyür; belleğe sığdığı sürece bu büyüme hiçbir uyarı üretmez ve tam da sığdığı için fark
edilmez. Doğruluk ölçüsü daha keskin: 1.587.600 öğenin yalnız **1.260'ı** doğrudur, bunlar da
köşegen üzerindekilerdir. Kalan **1.586.340 öğe** bir abonenin tüketimini başka bir abonenin
hanesine bölmektedir, yani hiçbir gerçek karşılığı yoktur.

Raporlanan sayı ise bu iki ölçünün hiçbirini yansıtmaz. Kişi başı ortalama tüketim doğru dizide
36,938180 m³, sessiz dizide 36,497564 m³ çıkar; aradaki fark 0,440616 m³, yaklaşık yüzde 1,2. Bu
yayılımın en tehlikeli yanıdır: **yanlış sonuç makul görünür.** Bir bulgu 36,5 ile 36,9 arasında
oynadığında kimse biçim kontrolü yapmayı düşünmez. Sayının kendisi hatayı ele vermez; hatayı ele
veren tek şey **öğe sayısıdır** ve o sayı çoğu zaman rapora girmez.

İkinci sessiz durum daha küçüktür ve tam bu yüzden daha sinsidir. Üç dönemin ortalama tabanı üç
mevsim düzeltmesiyle çarpılacak; düzeltme sütun olarak yazılınca sonuç 3 değer yerine 9 değer
olur. Düzeltilmiş taban toplamı 83,901904 m³ yerine 251,846368 m³, yani 3,0017 katı çıkar. Buradaki
çarpan tam olarak 3 değildir ve bu ayrıntı önemlidir: tam bir katsayı görülse "bir yerde üçle
çarpmışım" denip aranabilirdi, 3,0017 ise hesabın kendisinden gelen bir sayı gibi durur.

Bu iki durumdan çıkan çalışma kuralı tek cümledir: **yayılım kullanılan her işlemde sonucun biçimi
yazılır ve beklenen öğe sayısıyla karşılaştırılır.** Kural sağlandığı için sonucun doğru olduğu
varsayılamaz; kuralın sağlanması yalnızca hesabın yapılabildiğini söyler. Yukarıdaki sekiz çiftin
ikisinde hesap yapılmadı ve bu iyi haberdi; ikisinde yapıldı ve kötü haber oydu.

## Kuralın Kazandırdığı

```python
# kazanc.py — MODELDIR: yayilimin kazanci. Donem basina taban cikarilacak.
# Elle yol tabani 3.780 ogeye kopyalar; yayilim kopyalamaz, dizini hesaplar.
TABAN = array("d", [9.80, 10.40, 11.20])   # kurgu donem tabani, m3

def kopyalayarak(v, t):
    genis = array("d", [t[j % DONEM] for j in range(len(v))])
    return array("d", [v[j] - genis[j] for j in range(len(v))]), sys.getsizeof(genis)

def yayilarak(v, t):
    return array("d", [v[j] - t[j % DONEM] for j in range(len(v))]), 0

K1, ek1 = kopyalayarak(OKUMA, TABAN)
K2, ek2 = yayilarak(OKUMA, TABAN)
sapan = sum(1 for a, b in zip(K1, K2) if abs(a - b) > 1e-9)
w = gen([26, 16, 16, 12])
print(w(["olcu", "kopyalayarak", "yayilarak", "oran"]))
print(w(["taban dizisinin bayti", sys.getsizeof(TABAN), sys.getsizeof(TABAN), "1x"]))
print(w(["ek olarak ayrilan bayt", ek1, ek2, "-"]))
print(w(["toplam ayrilan bayt", ek1 + sys.getsizeof(K1), ek2 + sys.getsizeof(K2),
         f"{(ek1+sys.getsizeof(K1))/(ek2+sys.getsizeof(K2)):.1f}x"]))
print(f"\niki yol ayni sonucu veriyor: {sapan} oge 1e-9 m3 esiginin ustunde sapiyor")
print(f"yayilim 3 degerlik tabani {len(OKUMA)} ogeye kopyalamadan uyguluyor; "
      f"kopyalanan surumde taban {sys.getsizeof(TABAN)} bayt yerine {ek1} bayt tutuyor")
```

```
olcu                          kopyalayarak       yayilarak        oran
taban dizisinin bayti                  104             104          1x
ek olarak ayrilan bayt               30320               0           -
toplam ayrilan bayt                  60640           30320        2.0x

iki yol ayni sonucu veriyor: 0 oge 1e-9 m3 esiginin ustunde sapiyor
yayilim 3 degerlik tabani 3780 ogeye kopyalamadan uyguluyor; kopyalanan surumde taban 104 bayt yerine 30320 bayt tutuyor
```

Kuralın kazancı bu tabloda duruyor ve hesaplanan sonuçla ilgili değildir — iki yol da aynı 3.780
değeri veriyor, sapma 1e-9 m³ eşiğinin üstünde tek öğede bile yok. Fark **kopyalamadadır**. Dönem
tabanını elle uygulamanın en doğrudan yolu, 3 değeri 3.780 öğeye genişletip iki eşit biçimi öğe öğe
çıkarmaktır; bu genişletme 30.320 bayt tutar ve toplam ayrılan bayt 60.640'a çıkar. Yayılım
genişletilmiş diziyi hiç kurmaz; küçük biçimin dizinini büyük biçimden **hesaplar** ve taban 104
bayt olarak kalır. Toplam ayrılan bayt yarıya, 30.320'ye iner.

Oran burada 2 kat çünkü genişletilen taraf sonuç dizisiyle aynı boyda. Küçük dizinin büyük diziye
oranı düştükçe kazanç büyür: aynı işlem 3 dönem yerine 3 tarife basamağıyla ve 100.000 satırlık bir
tabloyla yapılsaydı kopyalanan sürüm iki tam tablo, yayılım tek tablo tutardı. **Yayılımın
kazandırdığı şey hesap değil, kurulmayan dizidir** ve bir önceki bölümdeki bedelin de aynı yerden
geldiğine dikkat etmek gerekir: kurulmayan dizi ucuz olduğu için beklenmedik biçimdeki dizi de
ucuza kurulur ve dikkat çekmeden büyür.

## Özet

- Yayılım kuralı biçimleri sağdan hizalar ve her boyutta eşitlik ya da 1 arar; kural biçim uyumunu
  denetler, işlemin anlamını denetlemez.
- Sekiz biçim çiftinin 4'ü doğru sonuç, 2'si hata, 2'si sessizce beklenmedik biçimde bir dizi
  üretir.
- Hane sayısı satır olarak yazıldığında sonuç 1.260 öğe yerine 1.587.600 öğe olur; ayrılan bayt
  10.160'tan 12.700.880'e, yani 1.250 kat büyür.
- Sessiz dizinin 1.587.600 öğesinin yalnız 1.260'ı doğrudur; kalan 1.586.340 öğenin gerçek bir
  karşılığı yoktur ve raporlanan kişi başı ortalama 36,938180 yerine 36,497564 m³ çıkar.
- Dönem tabanı düzeltmesi 3 değer yerine 9 değer üretir ve düzeltilmiş taban toplamını
  83,901904 m³'ten 251,846368 m³'e, 3,0017 katına taşır.
- Kuralın kazancı kurulmayan dizidir: dönem tabanını kopyalayarak uygulamak 30.320 bayt ek yer
  ister, yayılım 0 bayt ister ve toplam ayrılan bayt 60.640'tan 30.320'ye iner.

## Sonraki Adım

Yayılım aynı biçimdeki iki diziyi öğe öğe eşleştirir ve bu, elde edilebilecek en basit çok dizili
işlemdir. Tarife hesabının kendisi ise öğe eşleştirmesi değildir: üç basamağın birim fiyatları ile
üç dönemin tüketimi çarpılıp toplandığında her sonuç değeri **bütün bir satır ile bütün bir
sütunun** birlikte hesabıdır. Sonraki ders bu işlemi — matris çarpımını ve ondan türeyen çözüm
problemini — elle döngüyle ve soyutlamayla yazar, geçiş sayılarını karşılaştırır ve sayısal
duyarlılığın nerede devreye girdiğini ölçer. Biçim uyumu orada da belirleyicidir, ama kural
değişir: yayılımda uyum sağdan hizalamayla aranırken çarpımda tek bir eşitlik aranır ve o eşitlik
sağlanmadığında işlem hiçbir koşulda yapılamaz.
