Ders 04 / 13
Çok Değişkenli İnceleme
Altı sütunluk bir korelasyon matrisi 15 çift taşır ve eşik dağılım tablosundan değil karıştırmadan gelir: 2.000 karıştırmada katsayı dağılımının yüzde 95'i 0,0354 çıkar ve 15 çiftin 5'i bu eşiği aşar — ama beşinden üçü tanım gereği, ikisi de abone numarası sütunu yüzünden aşar. Birbirinden tümüyle bağımsız üretilmiş sütunlarda çift sayısı 6'dan 190'a çıktığında eşiği aşan çift sayısı 0'dan 12'ye çıkar ve beklenen değer 9,5'tir; en yüksek katsayı 0,049 ile eşiğin belirgin üstündedir. Boyut azaltma tek soruya indirgenir: ölçüm ağı sütunlarında ilk iki bileşen değişimin yüzde 49,3'ünü, iki gizli sürücüden üretilen kümede yüzde 82,1'ini, bağımsız sütunlarda yalnız yüzde 35,0'ını taşır.
İçindekiler
Önceki ders iki sütunu birlikte inceledi ve tek bir çiftin katsayısına payını yazdı. Gerçek bir çözümlemede ise çiftler tek tek sorulmaz; bir tablo alınır ve bütün sayısal sütunların katsayıları aynı anda hesaplanır. Altı sütun 15 çift üretir, yirmi sütun 190 çift. Her çift ayrı bir sorudur ve her soru rastlantıya bir şans daha tanır.
Bu dersin ölçüsü karşılaştırma sayısının ürettiği sahte ilişkidir. Tümüyle bağımsız üretilmiş sütunlarda kaç çiftin eşiği aştığı sayılır ve bu sayının sütun sayısıyla nasıl büyüdüğü gösterilir. İkinci ölçü boyut azaltmanın kazancıdır ve tek bir soruya indirgenir: kaç bileşen değişimin ne kadarını taşıyor.
- EA16. Çok değişkenli inceleme (multivariate) ikiden çok sütuna aynı anda bakar. sütunlu bir korelasyon matrisi çift taşır; çift sayısı sütun sayısıyla karesel büyür.
- EA17. Matristeki her hücre ayrı bir sorudur. Tek bir çift için savunulabilir olan eşik, bütün çiftlere aynı anda uygulandığında eşiği aşan çift sayısını kendiliğinden büyütür.
- EA18. Eşik burada dağılım tablosundan değil karıştırmadan gelir: bir sütun kendi içinde 2.000 kez karıştırılır ve elde edilen katsayı dağılımının yüzde 95’i eşik alınır.
- EA19. Boyut azaltma (dimensionality reduction) bu derste tek bir soruyla geçer: kaç bileşen değişimin ne kadarını taşıyor. Yöntem seçimi, döndürme ve bileşenlerin yorumu yazılmaz.
- EA20. Bileşen payları korelasyon matrisinin özdeğerlerinden okunur; özdeğerlerin toplamı sütun sayısına eşittir ve pay olarak yazıldığında toplam 100 olur. Sütunlar birbirini tekrarlamıyorsa paylar eşite yakın dağılır.
Matris ve Eşiği
# kesif.py — MODELDIR: K03 ve K04'un kurgu olcum agi ayni tohumla yeniden # uretilir. Kume kurgudur; hicbir gercek abone, sayac ya da bolge temsil edilmez. import math TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF DONEM = ["2026-01", "2026-02", "2026-03"] TARIFE = [10, 25, 40] BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26), ("bati", 0.14, 14), ("merkez", 0.18, 23)] def uretec(t: int): """Dogrusal eslemeli uretec: tohum koda yazilidir, cikti kosumdan kosuma ayni.""" x = ((t ^ (t >> 16)) * 2246822507) & M32 x = ((x ^ (x >> 13)) * 3266489909) & M32 s = [(x ^ (x >> 16)) & M32] def sonraki() -> float: s[0] = (s[0] * 1664525 + 1013904223) & M32 return s[0] / 4294967296 return sonraki def ayrik(u: float, w: list[float]) -> int: 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])] k = {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2], "hane_kisi": ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05]), "memnuniyet": ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) + 1} (_elenen if r() < 0.046 else _abone).append(k) _gecerli = {a["abone_no"] for a 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"] not in _gecerli: r() continue OKUMA.append({"abone_no": k["abone_no"], "bolge": k["bolge"], "donem": DONEM[d], "tuketim_m3": t, "hane_kisi": k["hane_kisi"], "memnuniyet": k["memnuniyet"], "basamak": 1 if t < TARIFE[0] else 2 if t < TARIFE[1] else 3 if t < TARIFE[2] else 4}) r() def ort(v: list[float]) -> float: return sum(v) / len(v) def kor(x: list[float], y: list[float]) -> float: mx, my = ort(x), ort(y) sx = math.sqrt(sum((a - mx) ** 2 for a in x)) sy = math.sqrt(sum((b - my) ** 2 for b in y)) return sum((a - mx) * (b - my) for a, b in zip(x, y)) / (sx * sy) def hiza(w: list[int], sol: int = 1): """Ilk `sol` sutun sola, kalanlar saga yaslanir.""" return lambda h: "".join(str(v).ljust(w[i]) if i < sol else str(v).rjust(w[i]) for i, v in enumerate(h)) SUTUN = [("tuketim", [o["tuketim_m3"] for o in OKUMA]), ("basamak", [float(o["basamak"]) for o in OKUMA]), ("hane_kisi", [float(o["hane_kisi"]) for o in OKUMA]), ("memnuniyet", [float(o["memnuniyet"]) for o in OKUMA]), ("donem", [float(DONEM.index(o["donem"])) for o in OKUMA]), ("abone_no", [float(o["abone_no"]) for o in OKUMA])] K = len(SUTUN) m = hiza([12] + [11] * K) print(m(["sutun"] + [a[:9] for a, _ in SUTUN])) for i, (ad, x) in enumerate(SUTUN): print(m([ad] + [f"{kor(x, y):+.3f}" for _, y in SUTUN[:i + 1]])) KOSUM = 2000 def esik_95(x: list[float], tohum: int) -> float: """Sutun kendi kendine karistirilir; |katsayi| dagiliminin yuzde 95'i esiktir.""" r, n = uretec(tohum), len(x) mx = ort(x) d = [a - mx for a in x] kare = sum(a * a for a in d) deger = [] for _ in range(KOSUM): h = d[:] for i in range(n - 1, 0, -1): j = int(r() * (i + 1)) h[i], h[j] = h[j], h[i] deger.append(abs(sum(a * b for a, b in zip(d, h)) / kare)) return sorted(deger)[int(0.95 * KOSUM)] ESIK = esik_95(SUTUN[0][1], TOHUM + 901) cift = [(SUTUN[i][0], SUTUN[j][0], kor(SUTUN[i][1], SUTUN[j][1])) for i in range(K) for j in range(i + 1, K)] asan = [c for c in cift if abs(c[2]) >= ESIK] print(f"\n{K} sutun, {len(cift)} cift; {KOSUM} karistirmada |katsayi| dagiliminin " f"yuzde 95'i {ESIK:.4f}") print(f"esigi asan cift: {len(asan)} / {len(cift)}") for a, b, v in sorted(asan, key=lambda c: -abs(c[2])): print(f" {a} / {b}: {v:+.3f}")
sutun tuketim basamak hane_kisi memnuniye donem abone_no tuketim +1.000 basamak +0.883 +1.000 hane_kisi +0.010 +0.007 +1.000 memnuniyet -0.010 -0.015 -0.004 +1.000 donem -0.111 -0.116 +0.000 -0.006 +1.000 abone_no +0.031 +0.041 +0.046 -0.001 -0.005 +1.000 6 sutun, 15 cift; 2000 karistirmada |katsayi| dagiliminin yuzde 95'i 0.0354 esigi asan cift: 5 / 15 tuketim / basamak: +0.883 basamak / donem: -0.116 tuketim / donem: -0.111 hane_kisi / abone_no: +0.046 basamak / abone_no: +0.041
Altı sütun 15 çift üretti ve eşik 0,0354 çıktı. Eşik bir tablodan okunmadı: tüketim sütunu kendi içinde 2.000 kez karıştırıldı, her koşumda katsayı yeniden hesaplandı ve elde edilen dağılımın yüzde 95’i eşik olarak alındı. Bu eşiğin anlamı dardır ve tam olarak şudur — hiçbir ilişki yokken, tek bir çiftte, yüz koşumun beşinde bu büyüklükte bir katsayı görülür.
Eşiği aşan beş çift var, ama beşi de aynı türden değil. Tüketim ile basamak arasındaki +0,883 bir keşif değil bir tanımdır; basamak 10, 25 ve 40 m³ sınırlarıyla tüketimden hesaplanır. Basamak ile dönem arasındaki −0,116, tüketim ile dönem arasındaki −0,111’in aynısıdır, çünkü basamak tüketimin bir yeniden yazımıdır — iki satır aynı olguyu iki kez sayar. Geriye abone numarasını içeren iki çift kalır: abone numarası bir kayıt numarasıdır, hiçbir şeyin nedeni olamaz.
On beş çiftten beşi eşiği aştı ve rapora girecek bağımsız bulgu sayısı en fazla birdir. Matris kendisi bir bulgu üretmez; sorulacak soruların sayısını büyütür ve büyüdükçe eşiği aşan hücre bulmak kolaylaşır.
Çift Sayısı Bulgu Üretir
# cokluk.py — KURGU: birbiriyle hicbir ilgisi olmayan sutunlar uretilir ve ayni # esik butun ciftlere uygulanir. Aranan sey, esigi asan cift sayisidir. def bagimsiz(k: int, n: int, tohum: int) -> list[list[float]]: r = uretec(tohum) return [[r() + r() + r() for _ in range(n)] for _ in range(k)] BAGIMSIZ = bagimsiz(20, len(OKUMA), TOHUM + 902) _m = [ort(s) for s in BAGIMSIZ] _d = [[a - t for a in s] for s, t in zip(BAGIMSIZ, _m)] _n = [math.sqrt(sum(a * a for a in s)) for s in _d] ikili = lambda i, j: sum(a * b for a, b in zip(_d[i], _d[j])) / (_n[i] * _n[j]) g = hiza([8, 8, 12, 12, 12]) print(g(["sutun", "cift", "esigi asan", "beklenen", "en buyuk"]) + " en buyuk cift") for k in (4, 6, 8, 12, 20): ciftler = [(i, j) for i in range(k) for j in range(i + 1, k)] deger = {(i, j): abs(ikili(i, j)) for i, j in ciftler} enb = max(deger, key=deger.get) print(g([k, len(ciftler), sum(1 for v in deger.values() if v >= ESIK), f"{0.05 * len(ciftler):.1f}", f"{deger[enb]:.3f}"]) + f" sutun{enb[0] + 1} / sutun{enb[1] + 1}") print(f"\nesik {ESIK:.4f}; sutunlarin hicbiri digerinden turetilmemistir")
sutun cift esigi asan beklenen en buyuk en buyuk cift 4 6 0 0.3 0.021 sutun1 / sutun2 6 15 1 0.8 0.037 sutun2 / sutun6 8 28 2 1.4 0.048 sutun1 / sutun8 12 66 5 3.3 0.049 sutun6 / sutun12 20 190 12 9.5 0.049 sutun6 / sutun12 esik 0.0354; sutunlarin hicbiri digerinden turetilmemistir
Bu tablodaki sütunların hiçbiri diğerinden türetilmemiştir; hepsi ayrı çekilişlerden gelir ve aralarında hiçbir ilişki yoktur. Buna rağmen dört sütunda 0, altı sütunda 1, sekiz sütunda 2, yirmi sütunda 12 çift eşiği aşıyor.
Sayının nereden geldiği eşiğin tanımında yazılı. Eşik, tek bir çiftte yüz koşumun beşinde aşılan değerdir; 190 çifte aynı eşik uygulanınca yaklaşık 190 × 0,05 = 9,5 çiftin aşması beklenir. Gözlenen 12, beklenen 9,5’in yakınındadır. Yani eşiği aşan çiftler bir kusur değil, eşiğin kendi tanımının doğrudan sonucudur.
Tehlike, bu tablodan tek bir satırın çekilip alınmasındadır. “Altıncı ve on ikinci sütun arasında 0,049’luk bir ilişki bulundu, eşik 0,0354” cümlesi doğru sayılar içerir ve tümüyle uydurmadır: o çift 190 çift arasından en büyüğü olduğu için seçilmiştir. Bir katsayının yanında yalnız payı değil, kaç çift arasından seçildiği de yazılmak zorundadır. “Tek çiftten biri” ile “190 çiftten en büyüğü” aynı cümle değildir.
Karşılaştırma sayısını küçültmenin bir yolu da eşiği yükseltmek değil, sütun sayısını düşürmektir. Bu, sonraki bölümün konusudur.
Kaç Bileşen
# bilesen.py — boyut azaltmanin tek sorusu: kac bilesen degisimin ne kadarini # tasiyor. Paylar korelasyon matrisinin ozdegerlerinden okunur. def ozdeger(A: list[list[float]]) -> list[float]: """Simetrik matrisin ozdegerleri: kose disi en buyuk oge sifira inene dek dondurulur.""" n, M = len(A), [s[:] for s in A] for _ in range(200): p, q, en = 0, 1, 0.0 for i in range(n): for j in range(i + 1, n): if abs(M[i][j]) > en: p, q, en = i, j, abs(M[i][j]) if en < 1e-12: # kose disi ogeler bu esigin altina inince donme durur break th = (M[q][q] - M[p][p]) / (2 * M[p][q]) t = (1.0 if th >= 0 else -1.0) / (abs(th) + math.sqrt(th * th + 1)) c = 1 / math.sqrt(t * t + 1) s = t * c for k in range(n): kp, kq = M[k][p], M[k][q] M[k][p], M[k][q] = c * kp - s * kq, s * kp + c * kq for k in range(n): pk, qk = M[p][k], M[q][k] M[p][k], M[q][k] = c * pk - s * qk, s * pk + c * qk return sorted((M[i][i] for i in range(n)), reverse=True) def ortak_surucu(tohum: int) -> list[list[float]]: """KURGU: alti sutun iki gizli surucuden ve gurultuden uretilir.""" r = uretec(tohum) f1 = [r() + r() + r() - 1.5 for _ in range(len(OKUMA))] f2 = [r() + r() + r() - 1.5 for _ in range(len(OKUMA))] AGIRLIK = [(1.0, 0.0), (0.9, 0.2), (0.8, 0.3), (0.1, 1.0), (0.2, 0.9), (0.3, 0.8)] return [[a * x + b * y + 0.55 * (r() + r() + r() - 1.5) for x, y in zip(f1, f2)] for a, b in AGIRLIK] KUME = [("olcum agi", [x for _, x in SUTUN]), ("ortak surucu", ortak_surucu(TOHUM + 903)), ("bagimsiz", bagimsiz(6, len(OKUMA), TOHUM + 904))] b = hiza([14] + [9] * 6) print(b(["kume"] + [f"b{i + 1}" for i in range(6)]) + " ilk iki bilesen") for ad, S in KUME: oz = ozdeger([[kor(a, c) for c in S] for a in S]) toplam = sum(oz) print(b([ad] + [f"{100 * v / toplam:.1f}" for v in oz]) + f" {100 * (oz[0] + oz[1]) / toplam:.1f} yuzde") print(f"\npaylarin toplami her satirda 100; ozdegerlerin toplami sutun sayisidir ({len(SUTUN)})")
kume b1 b2 b3 b4 b5 b6 ilk iki bilesen olcum agi 31.9 17.4 16.7 16.2 15.9 1.9 49.3 yuzde ortak surucu 55.2 26.9 4.9 4.7 4.3 4.0 82.1 yuzde bagimsiz 17.8 17.2 16.7 16.4 16.3 15.5 35.0 yuzde paylarin toplami her satirda 100; ozdegerlerin toplami sutun sayisidir (6)
Üç satır boyut azaltmanın ne zaman iş yaptığını gösteriyor. Ortak sürücüden üretilen kümede altı sütun iki gizli değişkenden geliyor ve ilk iki bileşen değişimin yüzde 82,1’ini taşıyor; altı sütun yerine iki sayı yazmak değişimin yüzde 17,9’unu bırakmak demektir. Bağımsız sütunlarda paylar 17,8’den 15,5’e kadar neredeyse eşittir ve ilk iki bileşen yalnız yüzde 35,0 taşır: azaltılacak bir şey yoktur, çünkü sütunlar birbirini hiç tekrarlamaz.
Ölçüm ağı satırı ikisinin arasındadır. İlk bileşen yüzde 31,9 taşır, sonraki dördü ise 17,4 ile 15,9 arasında sıkışır. Asıl bilgi son sütundadır: altıncı bileşenin payı yüzde 1,9’a düşmüştür. Bu düşüş bir tekrarın işaretidir ve tekrarın ne olduğu ilk tablodan bilinir — tüketim ile basamak aynı şeyi iki kez yazar. Pay tablosu, hangi sütunların birbirini tekrarladığını söylemez, ama tekrar olup olmadığını tek bakışta verir.
İki bölüm burada birleşiyor. Altı sütun 15 çift üretir; sütunlar iki bileşene indirilirse çift sayısı 1’e iner. Boyut azaltmanın ölçülebilir kazancı budur: bakılacak hücre sayısını düşürür ve böylece rastlantının eşiği aşma şansını da düşürür. Bedeli, bileşenlerin artık “tüketim” ya da “hane kişi sayısı” gibi bir adı olmamasıdır. Yöntem seçimi ve bileşenlerin yorumlanması bu dersin dışındadır.
Özet
- Altı sütunlu matris 15 çift taşır; eşik dağılım tablosundan değil karıştırmadan gelir ve 2.000 koşumluk dağılımın yüzde 95’i olarak 0,0354 çıkar.
- Eşiği aşan beş çiftin üçü tanım gereği aşar (basamak tüketimden hesaplanır), ikisi abone numarası sütunundan gelir; bağımsız bulgu sayısı en fazla birdir.
- Birbiriyle hiç ilgisi olmayan sütunlarda çift sayısı 6’dan 190’a çıktığında eşiği aşan çift sayısı 0’dan 12’ye çıkar ve beklenen değer 9,5’tir.
- Bir katsayının yanına payıyla birlikte kaç çift arasından seçildiği yazılır; “tek çiftten biri” ile “190 çiftten en büyüğü” aynı iddia değildir.
- Bileşen payları boyut azaltmanın kazancını önceden söyler: ortak sürücülü kümede ilk iki bileşen yüzde 82,1, ölçüm ağında yüzde 49,3, bağımsız sütunlarda yüzde 35,0 taşır.
Sonraki Adım
Bu konunun dört dersi kümeye hep hesapla yaklaştı: ortalama alındı, dağılım sayıldı, katsayı hesaplandı, matris kuruldu. Hepsinin ortak varsayımı, kümedeki değerlerin ölçülmüş değerler olduğuydu. Oysa keşif sırasında ilk yakalanan şeyler çoğu zaman hesapla değil, tabloya bakarken görülür: aynı değerin şüpheli sıklıkta tekrarı, bir üst sınırda biriken kayıtlar, birlikte bulunmaması gereken alan bileşimleri, bir dönemin diğerlerinden belirgin biçimde seyrek olması. Sonraki ders bu ilk denetimi ele alır ve her yakalanan sorunun hangi özeti ne kadar oynattığını sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.