Kitaplar / Yöntem ile Makine Öğrenmesi / Bölüm 3 — Denetimsiz öğrenme
Bölüm 3 — Denetimsiz öğrenme
Denetimsiz öğrenmede doğru cevaplar yoktur; algoritma verinin kendi yapısını bulur. Kümeleme benzer noktaları gruplar, boyut azaltma ise veriyi daha az sayıyla özetler. Bu yöntemler genellikle bir projenin ilk adımıdır: veriyi tanımak, görselleştirmek, aykırıları bulmak.
9. K-ortalamalar
Fikir. k merkez seçeriz. Her nokta en yakın merkeze atanır, sonra her merkez kendi noktalarının ortalamasına taşınır. Bu iki adım, atamalar değişmeyene kadar tekrarlanır.
program KOrtalamalar
{ Etiketsiz noktaları k kümeye ayırır. İki adım sırayla tekrarlanır:
1) Atama: her nokta en yakın merkeze atanır. 2) Güncelleme: her merkez, kümesinin ortalamasına taşınır.
Amaç (eylemsizlik): Σ ‖x − merkez‖² her turda küçülür ya da aynı kalır. }
kullan Matematik
değişken
P, merkez: ondalık dizisi dizisi
küme: tamsayı dizisi
i, c, tur, k: tamsayı
üyeler: ondalık dizisi dizisi
bulut: ondalık dizisi
fonksiyon U2(a, b: ondalık dizisi): ondalık
başla
sonuç := (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2
bitir
başla
Tohum(5)
P := []
{ üç bulut: (0,0), (5,1), (2,5) çevresinde 15'er nokta }
[[0, 0], [5, 1], [2, 5]] içindeki her bulut için
1'den 15'e kadar her i için P.Ekle([bulut[0] + Normal(0, 0.8), bulut[1] + Normal(0, 0.8)])
k := 3
merkez := [P[0], P[1], P[2]] { kötü başlangıç: hepsi aynı buluttan }
küme := Eşle(P, fonksiyon(p: ondalık dizisi) => 0)
1'den 6'ya kadar her tur için
başla
0'dan Uzunluk(P) - 1'e kadar her i için
küme[i] := Sırala([0, 1, 2], fonksiyon(j: tamsayı) => U2(P[i], merkez[j]))[0]
0'dan k - 1'e kadar her c için
başla
üyeler := []
0'dan Uzunluk(P) - 1'e kadar her i için eğer küme[i] = c ise üyeler.Ekle(P[i])
merkez[c] := [Toplam(Eşle(üyeler, fonksiyon(p: ondalık dizisi) => p[0])) / Uzunluk(üyeler),
Toplam(Eşle(üyeler, fonksiyon(p: ondalık dizisi) => p[1])) / Uzunluk(üyeler)]
bitir
yaz(Biçimle('Tur {}: eylemsizlik {:7.2} merkezler ', tur,
Toplam(Eşle(Aralık(Uzunluk(P)), fonksiyon(j: tamsayı) => U2(P[j], merkez[küme[j]])))), 0)
yaz(Eşle(merkez, fonksiyon(m: ondalık dizisi) => [Yuvarla(m[0], 1), Yuvarla(m[1], 1)]), 1)
bitir
bitir.Programın çıktısı şöyledir:
Tur 1: eylemsizlik 324.04 merkezler [[1.2, 3.1], [4.2, 1.0], [-0.1, -1.8]]
Tur 2: eylemsizlik 83.05 merkezler [[2.1, 5.0], [5.0, 1.2], [0.2, -0.4]]
Tur 3: eylemsizlik 70.41 merkezler [[2.3, 5.2], [5.0, 1.2], [0.1, -0.3]]
Tur 4: eylemsizlik 70.41 merkezler [[2.3, 5.2], [5.0, 1.2], [0.1, -0.3]]
Tur 5: eylemsizlik 70.41 merkezler [[2.3, 5.2], [5.0, 1.2], [0.1, -0.3]]
Tur 6: eylemsizlik 70.41 merkezler [[2.3, 5.2], [5.0, 1.2], [0.1, -0.3]]Ne öğrendik. Üç merkez de aynı buluttan başladığı halde algoritma 3 turda gerçek merkezleri (0,0), (5,1), (2,5) yaklaşık olarak buldu. k-ortalamalar k’yi sizin seçmenizi ister ve yuvarlak, benzer büyüklükte kümeler varsayar; halka gibi biçimlerde başarısız olur (bkz. DBSCAN). Hazır sürümü MakineOgrenmesi birimindeki KOrtalamalar fonksiyonudur.
Alıştırma. k := 2 ve k := 4 ile çalıştırınız (merkez listesini de buna göre ayarlayınız). Eylemsizlik k ile nasıl değişiyor? “Dirsek yöntemi” bu eğriye bakarak k’yi seçer.
10. Hiyerarşik kümeleme
Fikir. Her nokta kendi kümesiyle başlar; her adımda birbirine en yakın iki küme birleşir. Birleşmelerin sırası ve yüksekliği bir ağaç (dendrogram) oluşturur. Ağacı hangi yükseklikten keserseniz o kadar küme elde edersiniz; k’yi önceden seçmek gerekmez.
program HiyerarşikKümeleme
{ Birleştirici (aşağıdan yukarı) kümeleme: her nokta kendi kümesiyle başlar; her adımda en yakın
iki küme birleşir. Birleşme sırası bir ağaç (dendrogram) oluşturur; ağacı istediğiniz yükseklikte
keserek istediğiniz sayıda küme elde edersiniz. Kümeler arası uzaklık: ortalama bağlantı. }
kullan Matematik
değişken
P: ondalık dizisi dizisi
adlar: metin dizisi
kümeler: tamsayı dizisi dizisi
a, b, i, j, enA, enB: tamsayı
d, enD: ondalık
fonksiyon Uzaklık(A, B: tamsayı dizisi): ondalık
değişken x, y: tamsayı
başla
sonuç := 0
A içindeki her x için
B içindeki her y için
sonuç := sonuç + Kök((P[x][0] - P[y][0]) ** 2 + (P[x][1] - P[y][1]) ** 2)
sonuç := sonuç / (Uzunluk(A) * Uzunluk(B))
bitir
fonksiyon Ad(K: tamsayı dizisi): metin
başla
sonuç := '{' + Birleştir(Eşle(K, fonksiyon(x: tamsayı) => adlar[x]), ' ') + '}'
bitir
başla
{ Altı şehrin kabaca konumu (yüz km cinsinden, doğu ve kuzey) }
adlar := ['İstanbul', 'Bursa', 'İzmir', 'Ankara', 'Konya', 'Kayseri']
P := [[2.9, 4.1], [2.9, 3.4], [0.9, 2.6], [5.9, 3.1], [5.3, 1.6], [7.7, 2.3]]
kümeler := Eşle(Aralık(Uzunluk(P)), fonksiyon(x: tamsayı) => [x])
i := 1
Uzunluk(kümeler) > 1 iken
başla
enD := 1e9
0'dan Uzunluk(kümeler) - 2'ye kadar her a için
a + 1'den Uzunluk(kümeler) - 1'e kadar her b için
başla
d := Uzaklık(kümeler[a], kümeler[b])
eğer d < enD ise başla enD := d; enA := a; enB := b bitir
bitir
yaz(Biçimle('Adım {}: {:5.2} yükseklikte {} + {}', i, enD, Ad(kümeler[enA]), Ad(kümeler[enB])), 1)
kümeler[enA] := kümeler[enA] + kümeler[enB]
kümeler.Sil(enB)
eğer Uzunluk(kümeler) = 3 ise yaz(' → 3 kümede kesilirse: ' + Birleştir(Eşle(kümeler, @Ad), ', '), 1)
i := i + 1
bitir
bitir.Programın çıktısı şöyledir:
Adım 1: 0.70 yükseklikte {İstanbul} + {Bursa}
Adım 2: 1.62 yükseklikte {Ankara} + {Konya}
Adım 3: 2.23 yükseklikte {Ankara Konya} + {Kayseri}
→ 3 kümede kesilirse: {İstanbul Bursa}, {İzmir}, {Ankara Konya Kayseri}
Adım 4: 2.33 yükseklikte {İstanbul Bursa} + {İzmir}
Adım 5: 4.34 yükseklikte {İstanbul Bursa İzmir} + {Ankara Konya Kayseri}Ne öğrendik. En son birleşme (4,34) öncekilerden çok daha yüksektedir: veri doğal olarak iki gruba (batı ve iç Anadolu) ayrılır. Birleşme yüksekliklerindeki büyük sıçrama, kaç küme seçileceğine dair iyi bir ipucudur. Yöntem tüm çiftlerin uzaklığını hesapladığı için binlerce noktada yavaşlar.
Alıştırma. Uzaklık fonksiyonunu ortalama yerine en kısa uzaklığı (tek bağlantı) döndürecek şekilde değiştiriniz. Birleşme sırası değişiyor mu?
11. DBSCAN
Fikir. Kümeleri yoğunluktan tanımlarız. ε yarıçapında en az minNokta komşusu olan nokta bir “çekirdek”tir; birbirine yakın çekirdekler zincir gibi aynı kümeye bağlanır. Hiçbir çekirdeğe ulaşamayan noktalar gürültü olarak işaretlenir. Küme sayısı önceden verilmez ve kümeler her biçimde olabilir.
program DBSCAN
{ Yoğunluğa dayalı kümeleme. ε yarıçaplı komşuluğunda en az minNokta nokta bulunan noktalar "çekirdek"tir.
Birbirine ε'dan yakın çekirdekler aynı kümeye girer; hiçbir çekirdeğe ulaşamayan noktalar gürültüdür.
Küme sayısını önceden vermek gerekmez ve kümeler her biçimde olabilir (burada bir halka). }
kullan Matematik
değişken
P: ondalık dizisi dizisi
etiket: tamsayı dizisi { −2: ziyaret edilmedi, −1: gürültü, 0, 1, …: küme }
i, j, c, kume: tamsayı
açı, eps: ondalık
kuyruk, kom: tamsayı dizisi
minNokta: tamsayı
fonksiyon Komşular(i: tamsayı): tamsayı dizisi
başla
sonuç := Süz(Aralık(Uzunluk(P)), fonksiyon(j: tamsayı) =>
Kök((P[i][0] - P[j][0]) ** 2 + (P[i][1] - P[j][1]) ** 2) <= eps)
bitir
başla
Tohum(2)
P := []
0'dan 39'a kadar her i için { yarıçapı 4 olan halka }
başla
açı := i * 2 * Matematik.pi / 40
P.Ekle([4 * Cos(açı) + Normal(0, 0.2), 4 * Sin(açı) + Normal(0, 0.2)])
bitir
1'den 15'e kadar her i için P.Ekle([Normal(0, 0.4), Normal(0, 0.4)]) { ortada yoğun bir bulut }
P := P + [[7, 7], [-6, 5], [6, -6]] { üç aykırı nokta }
eps := 1.5; minNokta := 3
etiket := Eşle(P, fonksiyon(p: ondalık dizisi) => -2)
kume := 0
0'dan Uzunluk(P) - 1'e kadar her i için
başla
eğer etiket[i] <> -2 ise devam
kom := Komşular(i)
eğer Uzunluk(kom) < minNokta ise başla etiket[i] := -1; devam bitir
{ yeni küme: çekirdekten başlayıp ulaşılabilen herkesi genişleyerek ekle }
etiket[i] := kume
kuyruk := kom
Uzunluk(kuyruk) > 0 iken
başla
j := kuyruk.Çıkar(0)
eğer etiket[j] = -1 ise etiket[j] := kume { gürültü sanılan bir sınır noktası }
eğer etiket[j] <> -2 ise devam
etiket[j] := kume
kom := Komşular(j)
eğer Uzunluk(kom) >= minNokta ise kuyruk := kuyruk + kom
bitir
kume := kume + 1
bitir
yaz('Bulunan küme sayısı: ' + kume, 1)
0'dan kume - 1'e kadar her c için
yaz(Biçimle(' Küme {}: {} nokta', c, Uzunluk(Süz(etiket, fonksiyon(e: tamsayı) => e = c))), 1)
yaz(' Gürültü: ' + Eşle(Süz(Aralık(Uzunluk(P)), fonksiyon(j: tamsayı) => etiket[j] = -1), fonksiyon(j: tamsayı) => P[j]), 1)
bitir.Programın çıktısı şöyledir:
Bulunan küme sayısı: 2
Küme 0: 40 nokta
Küme 1: 15 nokta
Gürültü: [[7, 7], [-6, 5], [6, -6]]Ne öğrendik. DBSCAN halkayı (40 nokta) ve ortadaki bulutu (15 nokta) iki ayrı küme olarak buldu, üç aykırı noktayı da gürültü diye ayırdı. k-ortalamalar aynı veride halkayı dilimlere bölerdi. Bunun bedeli, ε seçimine duyarlılıktır. ε = 1,2 ile halka, noktalar arasındaki küçük boşluklardan üç parçaya kopar.
Alıştırma. eps := 1.2 ve eps := 5 deneyiniz. İkincisinde ne oluyor, neden?
12. Temel bileşenler analizi (PCA)
Fikir. Veri bulutunun en çok yayıldığı yönü buluruz; bu yön birinci temel bileşendir. Ona dik ve en çok yayılan ikinci yön ikinci bileşendir; böyle devam eder. Matematikte bu yönler kovaryans matrisinin özvektörleridir. Az sayıda bileşeni tutarak veriyi bilgi kaybetmeden küçültebiliriz.
program TemelBileşenler
{ Temel Bileşenler Analizi (PCA): veriyi en çok yayıldığı yönlere döndürür.
1) Veriyi ortala. 2) Kovaryans matrisini kur: C = XᵀX / (n − 1).
3) C'nin özvektörleri yönleri, özdeğerleri o yöndeki varyansı verir. En büyükleri tutup boyut azaltılır.
Özvektörü "kuvvet yinelemesi"yle buluyoruz: v ← C·v / ‖C·v‖ işlemi en büyük özvektöre yakınsar. }
kullan YZ, Matematik
değişken
X, C, v, Cv, v2: tensör
boy, kilo: ondalık dizisi
i: tamsayı
l1, l2: ondalık
başla
{ 8 kişinin boyu (cm) ve kilosu (kg): iki öznitelik güçlü biçimde ilişkili }
boy := [160, 165, 170, 172, 175, 180, 185, 190]
kilo := [55, 60, 63, 70, 72, 78, 85, 90]
X := Tensör([boy, kilo]).T { 8 × 2 matris }
X := X - X.Ortalama(0) { her sütunu ortala }
C := X.T @ X / (8 - 1)
yaz('Kovaryans matrisi:', 1); yaz(C, 1)
v := Tensör([1.0, 0.0])
1'den 50'ye kadar her i için
başla
Cv := C @ v
v := Cv / Kök((Cv * Cv).Toplam.Değer)
bitir
l1 := (v @ C @ v).Değer
v2 := Tensör([-v[1], v[0]]) { 2 boyutta ikinci bileşen birinciye diktir }
l2 := (v2 @ C @ v2).Değer
yaz(Biçimle('1. bileşen: ({:.3}, {:.3}) varyans {:.1} → açıklanan oran %{:.1}', v[0], v[1], l1, 100 * l1 / (l1 + l2)), 1)
yaz(Biçimle('2. bileşen: ({:.3}, {:.3}) varyans {:.1} → açıklanan oran %{:.1}', v2[0], v2[1], l2, 100 * l2 / (l1 + l2)), 1)
yaz('Tek boyuta indirgenmiş veri (1. bileşen üzerindeki izdüşüm):', 1)
yaz(X @ v, 1)
bitir.Programın çıktısı şöyledir:
Kovaryans matrisi:
tensör([[101.125, 122.125],
[122.125, 149.4107]])
1. bileşen: (0.635, 0.773) varyans 249.8 → açıklanan oran %99.7
2. bileşen: (-0.773, 0.635) varyans 0.8 → açıklanan oran %0.3
Tek boyuta indirgenmiş veri (1. bileşen üzerindeki izdüşüm):
tensör([-22.1297, -15.0923, -9.6002, -2.922, 0.5278, 8.3379, 16.9206, 23.958])Ne öğrendik. Boy ve kilo neredeyse aynı bilgiyi taşıyor: birinci bileşen varyansın %99,7’sini açıklıyor. Bu bileşen kabaca “iri yapılılık” anlamına gelir; iki sayı yerine tek sayıyla hemen hemen hiç bilgi kaybetmeden çalışabiliriz. Birimleri farklı öznitelikleri (örneğin cm ve TL) PCA’dan önce standartlaştırmak gerekir; yoksa büyük sayılı öznitelik baskın çıkar.
Alıştırma. Üçüncü bir öznitelik olarak ayakkabı numarasını ekleyiniz (3 × 3 kovaryans). Kuvvet yinelemesiyle en büyük bileşeni bulunuz.
13. Gauss karışım modelleri (GMM)
Fikir. Verinin birkaç çan eğrisinin (normal dağılımın) üst üste gelmesinden oluştuğunu varsayarız. EM algoritması iki adımı tekrarlar: E adımında her noktanın hangi eğriden gelmiş olabileceği olasılıkla tahmin edilir; M adımında eğrilerin ortalaması, genişliği ve ağırlığı bu olasılıklarla güncellenir. k-ortalamaların “yumuşak” sürümüdür.
program GaussKarışım
{ Veriyi iki Gauss (normal) dağılımın karışımı olarak modeller ve parametreleri EM algoritmasıyla bulur.
E adımı: her nokta için "hangi dağılımdan gelmiş olabilir?" olasılıkları (sorumluluklar) hesaplanır.
M adımı: her dağılımın ortalaması, sapması ve ağırlığı bu olasılıklarla yeniden hesaplanır.
k-ortalamalardan farkı: atamalar kesin değil, olasılıklıdır. }
kullan Matematik
değişken
X, r: ondalık dizisi { r[i]: i. noktanın 1. dağılıma ait olma olasılığı }
m1, m2, s1, s2, w1, p1, p2, n1, logOlabilirlik: ondalık
i, tur: tamsayı
fonksiyon Normal1(x, m, s: ondalık): ondalık
başla
sonuç := Üstel(-0.5 * ((x - m) / s) ** 2) / (s * Kök(2 * Matematik.pi))
bitir
başla
Tohum(4)
X := []
1'den 60'a kadar her i için X.Ekle(Normal(165, 6)) { 1. grup }
1'den 40'a kadar her i için X.Ekle(Normal(180, 5)) { 2. grup }
m1 := 160; m2 := 190; s1 := 10; s2 := 10; w1 := 0.5 { kaba bir başlangıç tahmini }
r := Eşle(X, fonksiyon(x: ondalık) => 0.0)
1'den 30'a kadar her tur için
başla
{ E adımı }
logOlabilirlik := 0
0'dan Uzunluk(X) - 1'e kadar her i için
başla
p1 := w1 * Normal1(X[i], m1, s1)
p2 := (1 - w1) * Normal1(X[i], m2, s2)
r[i] := p1 / (p1 + p2)
logOlabilirlik := logOlabilirlik + Ln(p1 + p2)
bitir
{ M adımı }
n1 := Toplam(r)
m1 := 0; m2 := 0
0'dan Uzunluk(X) - 1'e kadar her i için başla m1 := m1 + r[i] * X[i]; m2 := m2 + (1 - r[i]) * X[i] bitir
m1 := m1 / n1; m2 := m2 / (Uzunluk(X) - n1)
s1 := 0; s2 := 0
0'dan Uzunluk(X) - 1'e kadar her i için
başla
s1 := s1 + r[i] * (X[i] - m1) ** 2
s2 := s2 + (1 - r[i]) * (X[i] - m2) ** 2
bitir
s1 := Kök(s1 / n1); s2 := Kök(s2 / (Uzunluk(X) - n1))
w1 := n1 / Uzunluk(X)
eğer tur <= 3 veya tur mod 10 = 0 ise
yaz(Biçimle('Tur {:2}: log-olabilirlik {:8.2} | 1: ort {:6.1} sapma {:4.1} ağırlık {:.2} | 2: ort {:6.1} sapma {:4.1}',
tur, logOlabilirlik, m1, s1, w1, m2, s2), 1)
bitir
yaz(Biçimle('172 cm boyundaki biri 1. gruptan olasılıkla {:.2}', w1 * Normal1(172, m1, s1) /
(w1 * Normal1(172, m1, s1) + (1 - w1) * Normal1(172, m2, s2))), 1)
bitir.Programın çıktısı şöyledir:
Tur 1: log-olabilirlik -408.17 | 1: ort 165.9 sapma 6.1 ağırlık 0.64 | 2: ort 180.1 sapma 5.9
Tur 2: log-olabilirlik -355.73 | 1: ort 165.4 sapma 5.6 ağırlık 0.63 | 2: ort 180.6 sapma 5.3
Tur 3: log-olabilirlik -353.54 | 1: ort 165.2 sapma 5.2 ağırlık 0.63 | 2: ort 180.9 sapma 4.8
Tur 10: log-olabilirlik -352.10 | 1: ort 164.9 sapma 4.9 ağırlık 0.62 | 2: ort 181.0 sapma 4.5
Tur 20: log-olabilirlik -352.10 | 1: ort 164.8 sapma 4.8 ağırlık 0.61 | 2: ort 180.9 sapma 4.6
Tur 30: log-olabilirlik -352.09 | 1: ort 164.8 sapma 4.8 ağırlık 0.61 | 2: ort 180.8 sapma 4.6
172 cm boyundaki biri 1. gruptan olasılıkla 0.75Ne öğrendik. Veri gerçekte ortalaması 165 ve 180 olan 60 + 40 kişiden üretildi; EM, etiketleri hiç görmeden ortalamaları 164,8 ve 180,8, ağırlığı 0,61 (gerçek 0,60) buldu. Log-olabilirlik her turda artar; artış durunca algoritma yakınsamıştır. GMM’nin k-ortalamalara göre kazancı son satırda görülür: 172 cm’lik biri için kesin bir etiket değil, %75’lik bir olasılık verir.
Alıştırma. Başlangıç tahminini m1 := 170; m2 := 171 yapınız. Algoritma yine aynı çözüme ulaşıyor mu, kaç turda?