Ders 03 / 11
Hiyerarşik Kümeleme
Küme sayısını girdi olmaktan çıkarıp kesme kararına dönüştüren bir aile ve o kararın bedeli: aynı 200 abonede tek, tam ve ortalama bağlantı aynı ilk birleştirmeden (0,079) başlayıp 2,245, 8,917 ve 4,994'te biter; 2,0 yüksekliğinden kesildiğinde sırasıyla 3, 56 ve 37 küme verir. Dört kümede tek bağlantı 6,0849 ile rastgele atama tabanını yalnız 0,1492 geçer ve [1, 1, 1, 197] üretir, tam bağlantı 4,5419 ile 1,6922 geçer; iki bağlantı 200 abonenin 86'sını ayrı yerlere düşürür.
İçindekiler
Önceki dersin yordamı küme sayısını başlamadan önce istiyordu ve her koşum tek bir bölmeleme üretiyordu. Üç ayrı k için üç ayrı arama yapıldığında çıkan üç sonuç birbiriyle ilişkisizdi: üç kümeli bölmelemenin kümeleri, beş kümeli bölmelemenin kümelerinin birleşimi değildi. Dirseğin üç ayrı okuması üç ayrı k seçtiğine göre bu, karar verilemeyen bir noktada üç ilişkisiz cevap demekti.
Bu ders sırayı tersine çevirir. Her abone kendi kümesiyle başlar, her adımda en yakın iki küme birleştirilir ve 200 aboneden tek kümeye kadar iç içe geçmiş bir aile üretilir. Küme sayısı artık girdi değildir; ağacın hangi yükseklikten kesildiği sorusunun yanıtıdır. Buna karşılık yeni bir karar belirir ve dersin ölçtüğü şey odur: “en yakın iki küme” ifadesi nokta uzaklığından türetilemez, çünkü iki küme arasındaki uzaklığın kendisi ayrıca tanımlanmalıdır.
- KU16. Küme, sütunlar ve benzerlik tanımı önceki dersteki gibidir; ölçek yine 756 abonelik eğitim kümesinden öğrenilir. Kümeleme ise ilk 200 abone üzerinde yapılır: birleştirmeli yordamın maliyeti nokta sayısının küpüyle büyür. Bu bir ölçek kararıdır ve buradaki sayılar 756 abone için değil, bu 200 abone içindir.
- KU17. Nokta uzaklığı standart puanlarda kare uzaklığın kareköküdür; birleştirme yükseklikleri sütun birimiyle okunabilsin diye karekök alınır.
- KU18. Bağlantı ölçütü, iki küme arasındaki uzaklığın tanımıdır. Üçü denenir: tek bağlantı en yakın nokta çiftini, tam bağlantı en uzak nokta çiftini, ortalama bağlantı bütün nokta çiftlerinin ortalamasını alır.
- KU19. Birleştirme yüksekliği, o adımda birleştirilen iki küme arasındaki bağlantı uzaklığıdır; ölçüte özgüdür ve ölçütler arasında karşılaştırılamaz.
- KU20. Yordam belirlenimcidir; başlangıç seçimi yoktur ve eşit uzaklıkta iki aday çıkarsa küçük numaralı çift seçilir.
- KU21. Ölçü yine küme içi toplam uzaklıktır, taban çizgileri rastgele atama ve tek kümedir. Ağaçtan k küme okumak için kökten başlanır ve en yüksek dal, k dal kalana kadar açılır.
- KU22. İki bölmelemenin ayrışması iki ölçüyle verilir: ayrışan nokta çifti oranı ve en iyi küme eşleştirmesiyle ayrı düşen nokta sayısı; ikincisi için dört kümenin 24 eşleştirmesi denenir.
- KU23. Ölçüt, önceki dersin yordamının doğrudan en küçüğe indirmeye çalıştığı sayıdır; hiyerarşik yordamlar onu hedeflemez. Karşılaştırma bu yüzden ölçütün lehinedir.
Birleştirerek Kurulan Ağaç
Yordamın iskeleti kısadır: kümeler arası uzaklıklar tutulur, en küçüğü bulunur, iki küme birleştirilir ve yeni kümenin ötekilere uzaklığı bağlantı ölçütünün kuralıyla eskilerinden hesaplanır. Bu son adım yordamı ucuzlatır — birleşme sonrası hiçbir nokta çiftine yeniden bakılmaz. Üç ölçüt yalnız o tek satırda ayrılır.
# hiyerarsik.py — MODELDIR. Ayni KURGU abone tablosu, ayni tohum, ayni standart # puan tanimi; etiket yine uretilmez. import itertools import math import statistics TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF BOLGE = [(0.28, 21), (0.22, 17), (0.18, 26), (0.14, 14), (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 VERI = [] for i in range(HAM): r = uretec(TOHUM + i) temel = BOLGE[ayrik(r(), [x[0] for x in BOLGE])][1] 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]) if r() < 0.046: continue r, v = uretec(TOHUM + 17001 + i), [] for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])): v.append(0.0 if r() < 0.038 else math.floor( temel * math.exp((r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100) r() if v: x = {"ort_tuketim": round(sum(v) / len(v), 2), "oynaklik": round(max(v) - min(v), 2), "hane": hane, "memnuniyet": memnun, "donem": len(v)} x["kisi_basi"] = round(x["ort_tuketim"] / hane, 3) VERI.append(x) ALAN = ["ort_tuketim", "oynaklik", "kisi_basi", "hane", "memnuniyet", "donem"] def karistir(veri, tohum): r, s = uretec(tohum), list(range(len(veri))) for i in range(len(s) - 1, 0, -1): j = int(r() * (i + 1)) s[i], s[j] = s[j], s[i] return [veri[i] for i in s] EGT = karistir(VERI, TOHUM + 90000)[:756] HAM_V = [[x[a] for a in ALAN] for x in EGT] ORT = [statistics.fmean(c) for c in zip(*HAM_V)] SAP = [statistics.pstdev(c) for c in zip(*HAM_V)] V = [[(v[j] - ORT[j]) / SAP[j] for j in range(len(ALAN))] for v in HAM_V] ALT = 200 W = V[:ALT] kare = lambda a, b: sum((p - q) * (p - q) for p, q in zip(a, b)) merkez = lambda g: [statistics.fmean(c) for c in zip(*g)] uzak = lambda a, b: math.sqrt(kare(a, b)) BAGLANTI = {"tek": lambda da, db, na, nb: min(da, db), "tam": lambda da, db, na, nb: max(da, db), "ortalama": lambda da, db, na, nb: (na * da + nb * db) / (na + nb)} def birlestir(kural): # MODELDIR: en yakin iki kumeyi birlestir D = {(i, j): uzak(W[i], W[j]) for i in range(ALT) for j in range(i + 1, ALT)} ikili = lambda x, y: (x, y) if x < y else (y, x) etkin, boy, cocuk, yukseklik, yeni = list(range(ALT)), {i: 1 for i in range(ALT)}, {}, {}, ALT while len(etkin) > 1: a, b = min(((x, y) for i, x in enumerate(etkin) for y in etkin[i + 1:]), key=lambda p: (D[ikili(*p)], p)) cocuk[yeni], yukseklik[yeni] = (a, b), D[ikili(a, b)] for c in etkin: if c not in (a, b): D[ikili(c, yeni)] = kural(D[ikili(a, c)], D[ikili(b, c)], boy[a], boy[b]) boy[yeni] = boy[a] + boy[b] etkin = [c for c in etkin if c not in (a, b)] + [yeni] yeni += 1 return cocuk, yukseklik, boy, yeni - 1 AGAC = {ad: birlestir(kural) for ad, kural in BAGLANTI.items()} print(f"alt kume {ALT} abone; her baglanti olcutu {ALT - 1} birlestirme yapti") for ad, (_, yukseklik, _, _) in AGAC.items(): h = sorted(yukseklik.values()) print(f" {ad:<9} en kucuk birlestirme {h[0]:.3f}, ortanca {statistics.median(h):.3f}, " f"son uc {h[-3]:.3f} {h[-2]:.3f} {h[-1]:.3f}")
alt kume 200 abone; her baglanti olcutu 199 birlestirme yapti tek en kucuk birlestirme 0.079, ortanca 0.896, son uc 1.977 2.173 2.245 tam en kucuk birlestirme 0.079, ortanca 1.211, son uc 6.370 6.791 8.917 ortalama en kucuk birlestirme 0.079, ortanca 1.086, son uc 4.536 4.715 4.994
Üç ölçüt de aynı yerden başlıyor. İlk birleştirme her üçünde 0,079; tek nokta içeren iki küme arasında en yakın, en uzak ve ortalama çift aynı çift olduğu için ölçütler tek elemanlı kümelerde ayrışamaz. Ayrışma kümeler büyüdükçe başlıyor ve tepede uçurum var: son birleştirme tek bağlantıda 2,245, ortalama bağlantıda 4,994, tam bağlantıda 8,917. Yükseklik verinin değil ölçütün birimidir ve iki ağacın yükseklikleri yan yana okunamaz.
Ağaç Şeması ve Kesme Yüksekliği
Ağaç metin olarak basılır: her satır bir dalı, girinti dalın derinliğini, h birleştirme
yüksekliğini, n dalın altındaki abone sayısını verir. Üç düzeyle sınırlandırılmıştır, daha derin
dallar tek satırda özetlenir.
def sema(ad, ust=3, en_az=15): cocuk, yukseklik, boy, kok = AGAC[ad] print(f"agac semasi — {ad} baglanti, ust {ust} duzey") yig = [(kok, 0)] while yig: d, dr = yig.pop() if d in cocuk and boy[d] >= en_az and dr < ust: print(f" {' ' * dr}h={yukseklik[d]:.3f} n={boy[d]}") yig.extend((c, dr + 1) for c in sorted(cocuk[d], key=lambda c: boy[c])) else: print(f" {' ' * dr}dal n={boy[d]}") sema("ortalama") sema("tek") def kume_sayisi(ad, h): # h yuksekliginin ustunde kac birlestirme kaldi _, yukseklik, _, _ = AGAC[ad] return sum(1 for y in yukseklik.values() if y > h) + 1 print(f"\n{'kesme yuksekligi':>18}" + "".join(f"{ad:>12}" for ad in BAGLANTI)) for h in (1.0, 1.5, 2.0, 3.0, 4.0, 5.0): print(f"{h:>18.1f}" + "".join(f"{kume_sayisi(ad, h):>12}" for ad in BAGLANTI))
agac semasi — ortalama baglanti, ust 3 duzey
h=4.994 n=200
h=4.715 n=198
h=3.704 n=181
dal n=140
dal n=41
h=4.536 n=17
dal n=15
dal n=2
dal n=2
agac semasi — tek baglanti, ust 3 duzey
h=2.245 n=200
h=2.173 n=199
h=1.977 n=198
dal n=197
dal n=1
dal n=1
dal n=1
kesme yuksekligi tek tam ortalama
1.0 62 123 114
1.5 16 80 59
2.0 3 56 37
3.0 1 26 10
4.0 1 13 4
5.0 1 9 1
İki şema iki ayrı ağaç gösteriyor. Ortalama bağlantıda kök 200’ü 198 ile 2’ye, sonra 181 ile 17’ye, sonra 140 ile 41’e ayırıyor; her adımda iki yanı da dolu bir bölünme var. Tek bağlantıda ise her adımda tek bir abone kopuyor: 200’den 199, ondan 198, ondan 197. Sebep ölçütün tanımındadır — en yakın çifte bakıldığı için büyük bir kümeye yakın duran her nokta o kümeye eklenir. Ağaç bir zincire dönüşür ve üstten kesildiğinde verdiği şey bir bölmeleme değil, tek küme artı birkaç tek noktadır.
Alt tablo kesme yüksekliğinin ne olduğunu gösteriyor. 2,0 yüksekliğinden kesmek tek bağlantıda 3, ortalama bağlantıda 37, tam bağlantıda 56 küme verir; tek bir sayı, üç ölçütte on sekiz kat oynayan bir küme sayısına karşılık geliyor. 5,0’da tek ve ortalama bağlantı 1 küme derken tam bağlantı hâlâ 9 küme sayıyor. Kesme yüksekliği bu yüzden bir gözlem değil bir karardır; küme sayısını ağaçtan okuma iddiası, kararın yerini değiştirmekten başka bir şey yapmaz.
Bağlantı Ölçütünün Oynattığı Bölmeleme
Üç ağaç dört kümeye kadar açılıp aynı ölçüyle, aynı tabanla karşılaştırılır. Yanına önceki dersin merkez temelli yordamı da aynı 200 abone üzerinde konur.
def kesim_k(ad, k): # kokten baslayip en yuksek dali k'ya kadar ac cocuk, yukseklik, _, kok = AGAC[ad] dallar = [kok] while len(dallar) < k: d = max((x for x in dallar if x in cocuk), key=lambda x: yukseklik[x]) dallar = [x for x in dallar if x != d] + list(cocuk[d]) a = [0] * ALT for c, d in enumerate(dallar): yig = [d] while yig: x = yig.pop() if x in cocuk: yig.extend(cocuk[x]) else: a[x] = c return a def ic_uzaklik(a, k): # kume ici toplam uzaklik, nokta basina t = 0.0 for c in range(k): g = [W[i] for i in range(ALT) if a[i] == c] if g: t += sum(kare(v, merkez(g)) for v in g) return t / ALT def uyusmazlik(a, b): ay = sum((a[i] == a[j]) != (b[i] == b[j]) for i in range(ALT) for j in range(i + 1, ALT)) return 2 * ay / (ALT * (ALT - 1)) def ayri_nokta(a, b, k): # en iyi kume eslestirmesiyle uyusmayan nokta return ALT - max(sum(p[a[i]] == b[i] for i in range(ALT)) for p in itertools.permutations(range(k))) def k_ortalamalar(k, tohum, kosum=12): # 02. dersin yordami, ayni alt kumede r, en_iyi = uretec(tohum), None for _ in range(kosum): s = [] while len(s) < k: j = int(r() * ALT) if j not in s: s.append(j) M, a = [W[j] for j in s], None for _tur in range(60): y = [min(range(k), key=lambda c: kare(v, M[c])) for v in W] if y == a: break a = y M = [merkez([W[i] for i in range(ALT) if a[i] == c]) or M[c] for c in range(k)] u = ic_uzaklik(a, k) en_iyi = u if en_iyi is None else min(en_iyi, u) return en_iyi def rastgele_atama(k, tohum): # TABAN: hicbir yapi kullanmaz r = uretec(tohum) return [int(r() * k) for _ in range(ALT)] K = 4 P = {ad: kesim_k(ad, K) for ad in BAGLANTI} taban = statistics.fmean(ic_uzaklik(rastgele_atama(K, TOHUM + 33300 + t), K) for t in range(5)) print(f"k = {K}, {ALT} abone") print(f" {'taban - tek kume':<24} {ic_uzaklik([0] * ALT, K):.4f}") print(f" {'taban - rastgele atama':<24} {taban:.4f}") for ad in BAGLANTI: u = ic_uzaklik(P[ad], K) print(f" {ad + ' baglanti':<24} {u:.4f} fark {taban - u:+.4f}" f" kume boylari {sorted(P[ad].count(c) for c in range(K))}") print(f" {'k-ortalamalar (12 kosum)':<24} {k_ortalamalar(K, TOHUM + 44400):.4f}") print("\nbaglanti olcutleri arasi ayrisma") A = list(BAGLANTI) for i in range(3): for j in range(i + 1, 3): print(f" {A[i]:<9} - {A[j]:<9} nokta cifti {uyusmazlik(P[A[i]], P[A[j]]):.4f}, " f"ayri dusen nokta {ayri_nokta(P[A[i]], P[A[j]], K):>3} / {ALT}")
k = 4, 200 abone taban - tek kume 6.3473 taban - rastgele atama 6.2340 tek baglanti 6.0849 fark +0.1492 kume boylari [1, 1, 1, 197] tam baglanti 4.5419 fark +1.6922 kume boylari [6, 16, 65, 113] ortalama baglanti 5.0080 fark +1.2260 kume boylari [2, 2, 15, 181] k-ortalamalar (12 kosum) 3.4245 baglanti olcutleri arasi ayrisma tek - tam nokta cifti 0.5451, ayri dusen nokta 86 / 200 tek - ortalama nokta cifti 0.1477, ayri dusen nokta 17 / 200 tam - ortalama nokta cifti 0.4673, ayri dusen nokta 82 / 200
Tek bağlantının sayısı 6,0849 ve rastgele atama tabanını yalnız 0,1492 geçiyor. Küme boyları gerekçeyi veriyor: [1, 1, 1, 197]. Dört küme istendi, üç tanesi tek abone; sonuç öğrenmeyen bir yordamdan ayırt edilemeyecek kadar ona yakın. Tam bağlantı 4,5419 ile tabanı 1,6922 geçiyor ve boyları [6, 16, 65, 113] — en dengeli bölmeleme onunki, çünkü en uzak çifte bakan ölçüt geniş kümeleri cezalandırıyor. Ortalama bağlantı ikisinin arasında: 5,0080, fark 1,2260. Bağlantı ölçütünün seçimi, tabanı geçen farkı 0,1492 ile 1,6922 arasında, yani on bir kattan fazla oynatıyor.
Alt tablo aynı şeyi bölmeleme düzeyinde sayıyor. Tek ile tam bağlantı nokta çiftlerinin 0,5451’inde ayrışıyor ve en iyi eşleştirmeyle bile 86 abone ayrı yerlere düşüyor — 200 abonenin kırk üç yüzdesi. Tek ile ortalama bağlantı arasındaki ayrışma çok daha küçük, 17 abone; ortalama bağlantı da bir büyük kümeye eğilimli olduğu için tekle akraba kalıyor. Tam ile ortalama bağlantı ise 82 abonede ayrışıyor.
Son satırdaki 3,4245 dikkatli okunmalıdır. Önceki dersin merkez temelli yordamı bu ölçüde üçünü de açık farkla geçiyor, ama ölçü onun doğrudan en küçüğe indirmeye çalıştığı sayıdır; hiyerarşik yordamlar hiçbir adımda bu toplamı hesaplamaz bile. Karşılaştırma yordamların değerini değil, ölçütün kimin tarafında durduğunu gösteriyor. Ölçütü bağlantı uzaklıklarının tutarlılığı ya da zincirlemeye direnç olarak seçseydik sıralama tersine dönerdi.
Özet
- Birleştirmeli yordam küme sayısını girdi olmaktan çıkarır; iç içe geçmiş bir küme ailesi üretir ve karar kesme yüksekliğine taşınır.
- Üç bağlantı ölçütü aynı ilk birleştirmeden (0,079) başlar ama kökleri 2,245, 4,994 ve 8,917’dir; yükseklik ölçütün birimidir ve ölçütler arasında karşılaştırılamaz.
- 2,0 yüksekliğinden kesmek tek bağlantıda 3, ortalama bağlantıda 37, tam bağlantıda 56 küme verir.
- Dört kümede tek bağlantı 6,0849 ile rastgele atama tabanını yalnız 0,1492 geçer ve [1, 1, 1, 197] üretir; tam bağlantı 4,5419 ile 1,6922 geçer. Ölçütün seçimi farkı on bir kattan fazla oynatır.
- Tek ile tam bağlantı 200 abonenin 86’sını en iyi eşleştirmede bile ayrı yerlere düşürür; merkez temelli yordamın 3,4245’i ise ölçünün onun hedefi olmasıyla birlikte okunur.
Sonraki Adım
Üç derste dört yordam denendi — tek geçişli merkez seçimi, yinelemeli merkez güncellemesi ve üç bağlantı ölçütü — ve hepsi tek bir varsayımı paylaştı: her nokta bir kümeye atanmak zorundadır. Tek bağlantının [1, 1, 1, 197] bölmelemesi bu varsayımın bedelini gösteriyor. Üç abone kendi başına duruyor ama yordam onları “küme” ilan etmek zorunda kaldı, çünkü elinde başka bir kutu yok. Aynı biçimde, tam bağlantının 113 abonelik kümesinin kenarında duran ve hiçbir merkeze gerçekten yakın olmayan noktalar da bir kümeye yazıldı. Hiçbir kümeye ait olmayan nokta diye bir şey yoktu. Sonraki ders bu varsayımı kaldıran bir aileyi alır — noktaların yoğunluğuna bakan, seyrek bölgelerdeki noktaları gürültü olarak dışarıda bırakan ve küme sayısını hiç sormayan bir yordam — ve dışarıda bırakılan nokta sayısının kendisi bir ölçüye dönüşür.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.