İçeriğe geç
academia.sh

Ders 11 / 13

Regresyon ile İlişki Modelleme

En küçük kareler ders içinde yazılır ve bir katsayının ne söylediği ile ne söylemediği ayrılır: sayaç yaşının tek değişkenli katsayısı -0,605 m³/yıl, oynama payı [-0,714, -0,503] ve açıklanan değişim oranı 0,098 çıkar. Karıştırıcı değişken olarak bölge taban düzeyi eklendiğinde aynı katsayı 1,825'e döner, payı [1,629, 2,003] olur ve iki aralık hiç kesişmez. Beş bölgenin her birinde bölge içi eğim pozitiftir (0,771 ile 2,416 arasında). Açıklanan değişim oranı 0,098'den 0,505'e çıkar ama işareti haber vermez; tümüyle rastgele bir sütun eklendiğinde 0,505363'ten 0,505377'ye yine yükselir. Artıkların bölge ortalaması tek değişkenli modelde -3,020 ile 2,481 arasında gezinir, karıştırıcı eklendiğinde -0,229 ile 0,295 arasına iner.

İçindekiler

Önceki ders bir farkın kaç bileşimde ölçüldüğünü saydı, ama saydığı şey hep iki grup arasındaki farktı. Tüketimin sürekli bir değişkenle birlikte nasıl değiştiği hiç sorulmadı. İki grup yerine bir doğru sorulduğunda çıkan sayı bir fark değil, bir katsayıdır: değişken bir birim arttığında tüketimin ortalama kaç birim değiştiği.

Bu dersin sayısı katsayının oynama payıdır. Yanında ikinci bir sayı durur ve dersin asıl konusu odur: aynı katsayı, kümeye tek bir değişken eklendiğinde işaret değiştirir. Tahmin doğruluğu ölçütleri burada hesaplanmaz; ortalama mutlak hata, yanlılık ve bant Süreç, Ekip ve Teslimat kursunun Tahmin ve Planlama dersinde ölçüldü. Burada konu katsayının yorumu ve sınırıdır.

  • UI31. Küme K03’ten devralınır ve kurgudur. Abone düzeyine indirgenir: her abonenin değeri, dönemlerinin ortalamasıdır. 1.329 abonenin 1.260’ının en az bir okuması vardır.
  • UI32. Sayaç yaşı alanı da kurgudur ve iki bileşeni birlikte taşır: bölgeye bağlı bir bileşen ile bölge içi tüketim sapmasına bağlı bir bileşen. Amaç iki yönü tek değişkende toplamaktır.
  • UI33. En küçük kareler ders içinde yazılır: normal denklemler kurulur ve kısmi pivotlamalı elemeyle çözülür. Hazır çözücü kullanılmaz.
  • UI34. Katsayının oynama payı geri koyarak örneklemeyle üretilir: abone listesi 1.000 kez yeniden çekilir ve her çekimde model yeniden kurulur.
  • UI35. Karıştırıcı değişken bölge taban düzeyidir: bölgenin taban tüketimi hem sayaç yaşını hem tüketimi belirler.

Bir Katsayı ve Payı

En küçük kareler, artıkların karelerinin toplamını en küçük yapan katsayıları arar. Bu koşul normal denklemleri verir ve denklem takımı elemeyle çözülür. Aşağıdaki blok kümeyi kurar, çözücüyü yazar ve tek değişkenli modeli hesaplar.

# regresyon.py — MODELDIR. K03'un kurgu kumesi ayni tohumla uretilir ve abone
# duzeyine indirgenir. Sayac yasi alani da KURGUDUR: bolgeye bagli bir bilesenle
# bolge ici tuketim sapmasina bagli bir bileseni birlikte tasir.
import math

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def ayrik(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


ABONE, ELENEN = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    (ELENEN if r() < 0.046 else ABONE).append(
        {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2], "hane": hane,
         "memnuniyet": memnun})
GECERLI = {k["abone_no"] for k in ABONE}
OKUMA = {}
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:
            OKUMA.setdefault(k["abone_no"], []).append(t)
        r()

VERI = [dict(k, tuketim=sum(OKUMA[k["abone_no"]]) / len(OKUMA[k["abone_no"]]))
        for k in ABONE if k["abone_no"] in OKUMA]
BORT = {}
for x in VERI:
    BORT.setdefault(x["bolge"], []).append(x["tuketim"])
BORT = {b: sum(v) / len(v) for b, v in BORT.items()}
for x in VERI:
    r = uretec(TOHUM + 91000 + x["abone_no"])
    y = (14.0 - 0.75 * (x["taban"] - 20.5)
         + 0.15 * (x["tuketim"] - BORT[x["bolge"]]) + (r() + r() + r() - 1.5) * 2.4)
    x["yas"] = max(1, min(30, int(y + 0.5)))


def cozum(A, b):
    """Normal denklemleri kismi pivotlamali eleme ile cozer."""
    n = len(b)
    M = [A[i][:] + [b[i]] for i in range(n)]
    for i in range(n):
        p = max(range(i, n), key=lambda k: abs(M[k][i]))
        M[i], M[p] = M[p], M[i]
        for k in range(i + 1, n):
            f = M[k][i] / M[i][i]
            for j in range(i, n + 1):
                M[k][j] -= f * M[i][j]
    x = [0.0] * n
    for i in range(n - 1, -1, -1):
        x[i] = (M[i][n] - sum(M[i][j] * x[j] for j in range(i + 1, n))) / M[i][i]
    return x


def ekk(satirlar, alanlar):
    """En kucuk kareler: katsayilar ve aciklanan degisim orani."""
    p = len(alanlar) + 1
    A, b = [[0.0] * p for _ in range(p)], [0.0] * p
    for s in satirlar:
        v = [1.0] + [float(s[a]) for a in alanlar]
        for i in range(p):
            for j in range(p):
                A[i][j] += v[i] * v[j]
            b[i] += v[i] * s["tuketim"]
    kats = cozum(A, b)
    ort = sum(s["tuketim"] for s in satirlar) / len(satirlar)
    sst = sum((s["tuketim"] - ort) ** 2 for s in satirlar)
    sse = sum((s["tuketim"] - sum(k * x for k, x in
                                  zip(kats, [1.0] + [float(s[a]) for a in alanlar]))) ** 2
              for s in satirlar)
    return kats, 1 - sse / sst


ORNEKLEME = 1000
rs = uretec(TOHUM + 77000)


def katsayi_araligi(satirlar, alanlar, sira):
    """Geri koyarak ornekleme: abone listesi 1.000 kez yeniden cekilir."""
    n, cekilen = len(satirlar), []
    for _ in range(ORNEKLEME):
        ornek = [satirlar[int(rs() * n)] for _ in range(n)]
        cekilen.append(ekk(ornek, alanlar)[0][sira])
    cekilen.sort()
    return cekilen[24], cekilen[974]


print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, "
      f"{sum(len(v) for v in OKUMA.values())} okuma")
print(f"en az bir okumasi olan: {len(VERI)} abone")
kats, r2 = ekk(VERI, ["yas"])
alt, ust = katsayi_araligi(VERI, ["yas"], 1)
print(f"\ntuketim = {kats[0]:.3f} + ({kats[1]:.3f}) x sayac_yasi")
print(f"  sayac yasi katsayisi : {kats[1]:.3f} m3/yil")
print(f"  oynama payi          : [{alt:.3f}, {ust:.3f}]  ({ORNEKLEME} geri koyarak ornekleme)")
print(f"  aciklanan degisim    : {r2:.4f}   ({len(VERI)} gozlem)")
kurgu kume (tohum 20260218): 1329 abone, 3199 okuma
en az bir okumasi olan: 1260 abone

tuketim = 28.352 + (-0.605) x sayac_yasi
  sayac yasi katsayisi : -0.605 m3/yil
  oynama payi          : [-0.714, -0.503]  (1000 geri koyarak ornekleme)
  aciklanan degisim    : 0.0984   (1260 gozlem)

Rapor edilecek satır şudur: sayaç yaşı bir yıl arttığında ortalama tüketim 0,605 m³ düşüyor, oynama payı [-0,714, -0,503]. Aralık sıfırdan uzak ve dar; 1.260 gözleme dayanıyor. Bu sayı, kursun kuralını sağlıyor gibi görünür.

Katsayının yanındaki üçüncü sayı, açıklanan değişim oranı, 0,098. Tüketimdeki değişimin yaklaşık onda birini sayaç yaşı taşıyor. Bu düşük değer çoğu zaman “ilişki zayıf” diye okunur ve raporda tek satırlık bir uyarıya döner. Bu okuma eksiktir. Açıklanan değişim oranı ilişkinin gücü hakkında bir şey söyler; ilişkinin yönü hakkında hiçbir şey söylemez.

Karıştırıcı Değişken Katsayıyı Çevirir

Bölgenin taban tüketim düzeyi iki şeyi birden belirliyor: bölgede tüketim ne kadar yüksekse sayaçlar o kadar yenidir ve tüketim de o kadar yüksektir. Bu tanım bir karıştırıcı değişkendir. Modele girdiğinde katsayının ne olduğu ölçülebilir.

# Karistirici degisken: bolge taban duzeyi hem sayac yasini hem tuketimi belirler.
for x in VERI:
    r = uretec(TOHUM + 99000 + x["abone_no"])
    x["rastgele"] = r() * 10

MODEL = [("yas", ["yas"]), ("yas + taban", ["yas", "taban"]),
         ("yas + taban + memnuniyet", ["yas", "taban", "memnuniyet"]),
         ("yas + taban + rastgele", ["yas", "taban", "rastgele"])]
print("model                       yas katsayisi   aciklanan degisim")
for ad, alanlar in MODEL:
    k, r2 = ekk(VERI, alanlar)
    print(f"{ad:<28} {k[1]:>13.3f}   {r2:>17.6f}")

alt2, ust2 = katsayi_araligi(VERI, ["yas", "taban"], 1)
k1, _ = ekk(VERI, ["yas"])
k2, _ = ekk(VERI, ["yas", "taban"])
print(f"\nkatsayi              gozlenen   oynama payi")
print(f"tek degiskenli       {k1[1]:>8.3f}   [{alt:.3f}, {ust:.3f}]")
print(f"karistirici eklenmis {k2[1]:>8.3f}   [{alt2:.3f}, {ust2:.3f}]")

print("\nbolge   n   ort. sayac yasi   ort. tuketim   bolge ici egim")
for b in sorted(BORT, key=lambda b: -BORT[b]):
    alt_b = [x for x in VERI if x["bolge"] == b]
    e = ekk(alt_b, ["yas"])[0][1]
    print(f"{b:<7} {len(alt_b):>3}   {sum(x['yas'] for x in alt_b)/len(alt_b):>14.2f}"
          f"   {BORT[b]:>12.3f}   {e:>14.3f}")
model                       yas katsayisi   aciklanan degisim
yas                                 -0.605            0.098357
yas + taban                          1.825            0.505363
yas + taban + memnuniyet             1.827            0.505764
yas + taban + rastgele               1.825            0.505377

katsayi              gozlenen   oynama payi
tek degiskenli         -0.605   [-0.714, -0.503]
karistirici eklenmis    1.825   [1.629, 2.003]

bolge   n   ort. sayac yasi   ort. tuketim   bolge ici egim
dogu    219             9.95         24.814            2.416
merkez  231            12.13         22.483            2.154
kuzey   363            13.60         20.351            1.777
guney   258            16.69         16.728            1.550
bati    189            18.84         13.935            0.771

Katsayı -0,605’ten 1,825’e döndü. İki oynama payı, [-0,714, -0,503] ile [1,629, 2,003], hiç kesişmiyor. İki sayı da doğrudur ve ikisi de aynı kümeden çıkar; farklı olan tek şey hangi değişkenlerin modelde bulunduğudur.

Üçüncü tablo mekanizmayı açıkta gösteriyor. Bölgeler arasında yön nettir: sayaçların ortalama yaşı 9,95’ten 18,84’e çıkarken ortalama tüketim 24,814’ten 13,935’e düşüyor. Bölgelerin içinde ise beş bölgenin beşinde de eğim pozitiftir; en düşüğü 0,771, en yükseği 2,416. Tek değişkenli model bu iki yönü tek bir sayıda topluyor ve bölgeler arası yön ağır bastığı için sonuç negatif çıkıyor. Karıştırıcı değişken modele girdiğinde bölgeler arası yön ayrılıyor ve geriye bölge içi yön kalıyor.

İlk tablo, açıklanan değişim oranının ne söylemediğini iki ayrı şekilde veriyor. Birincisi: oran 0,098’den 0,505’e çıkarken katsayı işaret değiştirdi. Oranın yükselmesi, hangi işaretin doğru olduğunu söylemiyor; yalnız artıkların küçüldüğünü söylüyor. İkincisi: modele tümüyle rastgele üretilmiş bir sütun eklendiğinde oran 0,505363’ten 0,505377’ye yükseliyor. En küçük kareler her yeni sütuna en kötü ihtimalle sıfır katsayı verebildiği için bu oran hiçbir zaman düşmez. Değişken sayısı yazılmayan bir açıklanan değişim oranı karşılaştırılamaz.

Bir katsayı, “modeldeki öteki değişkenler sabitken” diye okunur ve bu okumanın tamamı modelin içindekilere bağlıdır. Katsayının söylediği şey ilişkidir; nedensellik değildir ve modelde bulunmayan bir değişkenin ne yaptığı hakkında hiçbir bilgi taşımaz.

Artıklar ve Payın Genişliği

Varsayım denetimi burada yapılır. Model doğru kurulmuşsa artıklar her kırılımda sıfır civarında toplanmalı ve değişkenlikleri tahmin düzeyiyle birlikte oynamamalıdır.

# Varsayim denetimi: artiklarin kirilimda ortalamasi ve tahmine gore degiskenligi.
def artiklar(satirlar, alanlar):
    kats = ekk(satirlar, alanlar)[0]
    cikti = []
    for s in satirlar:
        v = [1.0] + [float(s[a]) for a in alanlar]
        tahmin = sum(k * x for k, x in zip(kats, v))
        cikti.append((s, tahmin, s["tuketim"] - tahmin))
    return cikti


A1, A2 = artiklar(VERI, ["yas"]), artiklar(VERI, ["yas", "taban"])
print("bolge     n   artik ort. (yas)   artik ort. (yas + taban)")
for b in sorted(BORT, key=lambda b: -BORT[b]):
    d1 = [a for s, _, a in A1 if s["bolge"] == b]
    d2 = [a for s, _, a in A2 if s["bolge"] == b]
    print(f"{b:<7} {len(d1):>3}   {sum(d1)/len(d1):>16.3f}   {sum(d2)/len(d2):>24.3f}")


def sapma(d):
    o = sum(d) / len(d)
    return math.sqrt(sum((x - o) ** 2 for x in d) / len(d))


print("\ntahmin bandi      n   artik ortalamasi   artik degiskenligi")
sirali = sorted(A2, key=lambda t: t[1])
adim = len(sirali) // 4
for i in range(4):
    dilim = sirali[i * adim:(i + 1) * adim if i < 3 else len(sirali)]
    d = [a for _, _, a in dilim]
    print(f"{dilim[0][1]:>6.1f} - {dilim[-1][1]:>5.1f} {len(dilim):>5}   {sum(d)/len(d):>16.3f}"
          f"   {sapma(d):>18.3f}")

# Ayni katsayi, dortte bir gozlemle
r4 = uretec(TOHUM + 88000)
CEYREK = [x for x in VERI if r4() < 0.25]
a3, u3 = katsayi_araligi(CEYREK, ["yas", "taban"], 1)
k3 = ekk(CEYREK, ["yas", "taban"])[0][1]
print(f"\ngozlem sayisi   katsayi   oynama payi              genislik")
print(f"{len(VERI):>13}   {k2[1]:>7.3f}   [{alt2:.3f}, {ust2:.3f}]        {ust2 - alt2:>8.3f}")
print(f"{len(CEYREK):>13}   {k3:>7.3f}   [{a3:.3f}, {u3:.3f}]        {u3 - a3:>8.3f}")
bolge     n   artik ort. (yas)   artik ort. (yas + taban)
dogu    219              2.481                     -0.229
merkez  231              1.468                      0.295
kuzey   363              0.227                      0.031
guney   258             -1.526                     -0.118
bati    189             -3.020                      0.005

tahmin bandi      n   artik ortalamasi   artik degiskenligi
   8.7 -  16.5   315              0.293                3.891
  16.5 -  19.7   315             -0.168                3.988
  19.7 -  23.3   315             -0.346                4.852
  23.3 -  34.3   315              0.221                4.893

gozlem sayisi   katsayi   oynama payi              genislik
         1260     1.825   [1.629, 2.003]           0.374
          313     1.665   [1.341, 1.989]           0.648

İlk tablo tek değişkenli modelin kusurunu katsayıya bakmadan yakalıyor. Artıkların bölge ortalaması -3,020 ile 2,481 arasında geziniyor: model doğu bölgesini sistemli olarak eksik, batı bölgesini sistemli olarak fazla tahmin ediyor. Bir artık kümesinde kırılıma göre kalan bu düzen, modelin dışarıda bıraktığı bir değişkenin imzasıdır. Karıştırıcı eklendiğinde aynı sayılar -0,229 ile 0,295 arasına iniyor. Artık incelemesi, sonucu görmeden önce hangi modelin eksik olduğunu söylüyor.

İkinci tablo bir varsayımın karşılanmadığını gösteriyor. Artıkların değişkenliği tahmin düzeyiyle birlikte büyüyor: en düşük bantta 3,891, en yüksek bantta 4,893. Katsayı bu durumda hâlâ hesaplanır, ama tek bir oynama payı bütün tahmin aralığı için geçerli değildir; yüksek tüketimli abonelerde pay daha geniştir. Geri koyarak örnekleme bu düzensizliği kendiliğinden taşır, çünkü kümeyi olduğu gibi yeniden çeker.

Üçüncü tablo payın neye bağlı olduğunu veriyor. Aynı model dörtte bir gözlemle kurulduğunda katsayı 1,825’ten 1,665’e kayıyor ve oynama payının genişliği 0,374’ten 0,648’e çıkıyor. Gözlem sayısı dörtte bire indi, genişlik yaklaşık iki katına çıktı. Küçük kırılımda hesaplanan bir katsayının payı yazılmadan raporlanması, bu tablodaki iki satırı tek satır göstermektir.

Özet

  • Sayaç yaşının tek değişkenli katsayısı -0,605 m³/yıl, oynama payı [-0,714, -0,503] ve açıklanan değişim oranı 0,098’dir; sayı 1.260 gözleme dayanır.
  • Bölge taban düzeyi karıştırıcı değişken olarak eklendiğinde aynı katsayı 1,825 olur ve payı [1,629, 2,003] çıkar; iki aralık hiç kesişmez.
  • Mekanizma kırılımda görünür: bölgeler arasında ortalama yaş yükselirken ortalama tüketim düşer, buna karşılık beş bölgenin beşinde de bölge içi eğim pozitiftir (0,771 ile 2,416 arasında).
  • Açıklanan değişim oranı 0,098’den 0,505’e çıkarken katsayı işaret değiştirdi; oran yönü haber vermez ve tümüyle rastgele bir sütun eklendiğinde 0,505363’ten 0,505377’ye yine yükselir.
  • Artıkların bölge ortalaması tek değişkenli modelde -3,020 ile 2,481 arasında gezinir, karıştırıcı eklendiğinde -0,229 ile 0,295 arasına iner; artık değişkenliği tahminle birlikte 3,891’den 4,893’e büyür.
  • Dörtte bir gözlemle aynı katsayının payı 0,374’ten 0,648 genişliğe çıkar.

Sonraki Adım

Bu ders bir katsayının kırılıma göre yön değiştirdiğini gösterdi, ama kırılım hep bölgeydi ve zaman hiç işin içine girmedi. Aboneler ağa aynı anda katılmıyor ve aynı süre boyunca izlenmiyor. Sonraki ders kümeyi giriş dönemine göre böler: elde tutma oranı hesaplanır, sonra giriş penceresi ve gözlem penceresi değiştirilerek aynı kümeden kaç farklı oran çıktığı sayılır. Aynı yön değiştirme burada bir kez daha görünür, bu kez katsayıda değil oranda: toplulaştırılmış oran bir yönü, her kohortun oranı tersini gösterir.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat