Ders 08 / 11
Tekil Değer Ayrışımı Uygulaması
Bir dizeyi düşük ranklı bir yaklaşımla saklamanın hata ve sayı adedi cinsinden bedelinin ölçülmesi: elle kurulmuş 6x5'lik dizeyde rank 2 yaklaşımın toplam hatası 0,6746 ve bu sayı atılan tekil değerlerin karelerinin köküne birebir eşit, ama rank 3'te saklanan sayı 36'ya çıkıp özgün 30 sayıyı geçiyor. 252x12'lik abone tablosunda sütun ortalamalarıyla geri kurma 3,3411 verirken rank 2 yaklaşım 2,7464 veriyor ve 3.024 sayı yerine 554 sayı saklıyor; aynı bütçeyle rastgele iki ham sütun saklamak 3,0617 veriyor ve düşük ranklı yaklaşımın üstünlüğü rank 2'de 0,3153, rank 8'de 0,9663 oluyor.
İçindekiler
Önceki ders bileşen yönlerini eşdeğişim dizeyi üzerinden buldu ve her noktayı k yöne izdüşürüp geri kurdu. Ölçü nokta başına ortalama uzaklıktı ve sütun ortalamalarıyla geri kurma 3,3411 veriyordu. Yordamın sormadığı soru şuydu: bu gösterimi saklamak için kaç sayı gerekiyor. On iki sütunlu 252 satırlık bir tablo 3.024 sayıdır; iki bileşenli gösterim aynı tabloyu kaçla tutar.
Soru sorulduğu anda izdüşüm bir dizey işlemine dönüşür. Tablo, satırları abone ve sütunları ölçüm olan bir dizeydir; izdüşüm bu dizeyi iki küçük dizeyin çarpımı olarak yeniden yazmaktır. Tekil değer ayrışımı bunu yapan ayrışımdır: dizeyi, satır yönleri, sütun yönleri ve her yön çiftine bir ağırlık veren tekil değerler olarak üçe ayırır. İlk r tekil değeri tutup kalanı atmak düşük ranklı yaklaşım üretir. Bu dersin ölçtüğü şey o yaklaşımın iki tarafıdır: hata ne kadar artıyor ve saklanan sayı adedi ne kadar azalıyor.
- BA9. Ölçülen dizey sınama kümesidir: 252 satır, 12 sütun, 3.024 sayı. Sütunlar önceki dersteki ölçekle, yani yalnız eğitim kümesinden okunan ortalama ve standart sapmayla ölçeklenir.
- BA10. Ayrışım ders içinde yazılır ve modeldir: dizeyin sütun çarpım dizeyi kurulur, en büyük yön 300 yinelemede aranır, her yeni yön öncekilere diklenir, tekil değer bulunan büyüklüğün kökü olarak alınır. Kitaplık çağrılmaz ve ölçek küçük tutulur.
- BA11. Tekil değerler negatif değildir ve büyükten küçüğe sıralanır. Rank, sıfırdan farklı tekil değerlerin sayısıdır; eşik alınmıştır, çünkü yinelemeli arama sıfırı tam olarak değil yaklaşık üretir.
- BA12. Saklanan sayı adedi açıkça sayılır: rank r için satır katsayıları , sütun yönleri , tekil değerler , ve tabloyu özgün birimine döndürmek için 12 ortalama ile 12 standart sapma. Toplam .
- BA13. Geri kurma hatası tanımı önceki dersten sürer: nokta başına ortalama uzaklık, ölçeklenmiş uzayda, birimi standart sapma.
- BA14. Taban çizgisi yine sütun ortalamalarıyla geri kurmadır ve rank 0 satırıdır.
- BA15. Küçük dizey elle kurulmuştur, abone tablosundan gelmez ve yalnız ayrışımın ne yaptığını görünür kılmak içindir.
- BA16. İkinci karşılaştırma aynı bütçeyle r ham sütun saklamaktır: rastgele r sütun tutulur, kalan sütunlar ortalamayla kurulur, üç çekiliş ortalanır.
Ayrışım Küçük Bir Dizeyde
Altı satırlı, beş sütunlu bir dizey elle kurulur. Satırların çoğu iki temel örüntünün ağırlıklı toplamıdır: biri uçlarda yüksek ortada düşük, öbürü tam tersi. Üçüncü satırın ilk hücresi bilerek bir birim kaydırılmıştır, böylece dizey iki örüntüye tam oturmaz.
def carp(m, v): return [sum(m[i][j] * v[j] for j in range(len(v))) for i in range(len(m))] def diklestir(v, B): for u in B: c = sum(v[i] * u[i] for i in range(len(v))) v = [v[i] - c * u[i] for i in range(len(v))] return v def ayristir(A): # MODELDIR: tekil deger ayrisimi ders icinde, yalniz standart kitaplikla yazilir. m = len(A[0]) G = [[sum(s[i] * s[j] for s in A) for j in range(m)] for i in range(m)] sag, tekil = [], [] for _ in range(m): v, lam = [1.0 / (i + 1) for i in range(m)], 0.0 for _ in range(300): w = diklestir(carp(G, v), sag) u = sum(q * q for q in w) ** 0.5 if u < 1e-12: break v, lam = [q / u for q in w], u if lam < 1e-10: break sag.append(v) tekil.append(lam ** 0.5) sol = [[sum(s[j] * v[j] for j in range(m)) / tekil[i] for s in A] for i, v in enumerate(sag)] return sol, tekil, sag def yaklas(sol, tekil, sag, r, a, b): return sum(sol[i][a] * tekil[i] * sag[i][b] for i in range(r)) KUCUK = [[6, 3, 0, 3, 6], [4, 3, 2, 3, 4], [3, 3, 4, 3, 2], [0, 3, 6, 3, 0], [4, 4, 4, 4, 4], [2, 2, 2, 2, 2]] SOL, TEKIL, SAG = ayristir([[float(q) for q in s] for s in KUCUK]) print("tekil degerler: " + ", ".join(f"{s:.4f}" for s in TEKIL)) print(f"{'rank':>4} {'toplam hata':>12} {'atilanlarin koku':>17} {'saklanan':>9}") for r in range(len(TEKIL) + 1): h = sum((KUCUK[a][b] - yaklas(SOL, TEKIL, SAG, r, a, b)) ** 2 for a in range(6) for b in range(5)) ** 0.5 print(f"{r:>4} {h:>12.4f} {sum(s * s for s in TEKIL[r:]) ** 0.5:>17.4f} " f"{r * (6 + 5 + 1):>9}") print("ozgun dizey 30 sayi. rank 2 yaklasim:") for a in range(6): print(" " + " ".join(f"{yaklas(SOL, TEKIL, SAG, 2, a, b):6.2f}" for b in range(5)))
tekil degerler: 17.0637, 7.3058, 0.6746
rank toplam hata atilanlarin koku saklanan
0 18.5742 18.5742 0
1 7.3369 7.3369 12
2 0.6746 0.6746 24
3 0.0000 0.0000 36
ozgun dizey 30 sayi. rank 2 yaklasim:
6.03 2.99 0.01 2.99 5.98
4.07 2.98 2.02 2.98 3.95
2.54 3.12 3.90 3.12 2.34
0.16 2.96 6.04 2.96 -0.12
4.13 3.97 4.03 3.97 3.90
2.06 1.98 2.01 1.98 1.95
İki sütun birbirine birebir eşit. Rank r yaklaşımın toplam hatası, atılan tekil değerlerin karelerinin toplamının köküdür — rank 2’de hata 0,6746 ve atılan tek tekil değer de 0,6746. Bu, ayrışımın verdiği en kullanışlı şeydir: hata, yaklaşım kurulmadan önce, yalnız tekil değerler listesine bakılarak bilinir. Yordamı çalıştırıp ölçmeye gerek yoktur.
İkinci sütun okumayı tersine çevirir. Rank 2 yaklaşım 24 sayı saklar, özgün dizey 30 sayı; kazanç 6 sayıdır ve hata 0,6746’dır. Rank 3 yaklaşım hatasızdır ama 36 sayı saklar — özgün dizeyden 6 fazla. Tam ayrışım sıkıştırma değildir. Kazanç yalnız atılan ranktan gelir ve dizeyin kendisi küçükse hiç gelmeyebilir.
Yaklaşımın çıktısı da okunabilir. İlk, ikinci, dördüncü, beşinci ve altıncı satırlar neredeyse
birebir geri geliyor, çünkü onlar gerçekten iki örüntünün toplamıydı. Kaydırılmış üçüncü satır
3, 3, 4, 3, 2 yerine 2.54, 3.12, 3.90, 3.12, 2.34 dönüyor. Hatanın tamamı bu tek satırda
toplanmış durumda. Düşük ranklı yaklaşım hatayı eşit dağıtmaz; örüntüye uymayan satırı düzeltir
ve o satır hakkındaki bilgiyi atar.
Abone Tablosunda Rank ve Saklanan Sayı
Aynı ayrışım 252 satırlık, 12 sütunlu abone tablosuna uygulanır. Sütunlar önceki dersteki ölçekle ölçeklenir, ki taban çizgisi değişmesin.
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, VERI = [], [] 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]) if r() >= 0.046: ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun}) for k in ABONE: r, v = uretec(TOHUM + 7000 + k["no"]), [] 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( k["bolge"][2] * math.exp((r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100) r() if not v: continue ort = sum(v) / len(v) x = {"hane": k["hane"], "memnuniyet": k["memnuniyet"], "donem": len(v), "ort_tuketim": round(ort, 2), "oynaklik": round(max(v) - min(v), 2), "sifir_okuma": int(min(v) == 0.0), "kisi_basi": round(ort / k["hane"], 3)} for b in BOLGE: x["b_" + b[0]] = int(k["bolge"][0] == b[0]) VERI.append(x) ALAN = ["ort_tuketim", "oynaklik", "kisi_basi", "hane", "memnuniyet", "donem", "sifir_okuma", "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"] r, s = uretec(TOHUM + 90000), 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] K = [VERI[i] for i in s] EGT, SIN = K[:756], K[1008:] n = len(ALAN) ORT = {a: sum(x[a] for x in EGT) / len(EGT) for a in ALAN} SAC = {a: max(1e-9, (sum((x[a] - ORT[a]) ** 2 for x in EGT) / len(EGT)) ** 0.5) for a in ALAN} Z = [[(x[a] - ORT[a]) / SAC[a] for a in ALAN] for x in SIN] N = len(Z) SOL, TEKIL, SAG = ayristir(Z) def hata(r): return sum(sum((Z[a][b] - yaklas(SOL, TEKIL, SAG, r, a, b)) ** 2 for b in range(n)) ** 0.5 for a in range(N)) / N print(f"ozgun tablo {N} x {n} = {N * n} sayi, bulunan rank {len(TEKIL)}") print("tekil degerler: " + ", ".join(f"{s:.2f}" for s in TEKIL)) print(f"{'rank':>4} {'hata':>8} {'fark':>8} {'saklanan':>9} {'oran':>6}") for r in (0, 1, 2, 3, 4, 6, 8, 10, 11): print(f"{r:>4} {hata(r):>8.4f} {hata(r) - hata(0):>+8.4f} " f"{24 + r * (N + n + 1):>9} {(24 + r * (N + n + 1)) / (N * n):>6.3f}")
ozgun tablo 252 x 12 = 3024 sayi, bulunan rank 11 tekil degerler: 24.19, 21.44, 19.46, 18.48, 18.14, 16.64, 15.66, 14.15, 10.50, 7.14, 5.69 rank hata fark saklanan oran 0 3.3411 +0.0000 24 0.008 1 3.0129 -0.3282 289 0.096 2 2.7464 -0.5947 554 0.183 3 2.4284 -0.9127 819 0.271 4 2.1363 -1.2048 1084 0.358 6 1.5054 -1.8357 1614 0.534 8 0.7925 -2.5486 2144 0.709 10 0.2568 -3.0843 2674 0.884 11 0.0000 -3.3411 2939 0.972
Tekil değerler bu tabloda hiç dik inmiyor: en büyüğü 24,19, en küçüğü 5,69 ve arada bir uçurum yok. Küçük dizeyde iki tekil değer 17,06 ve 7,31 iken üçüncüsü 0,67’ye düşüyordu; orada rank 2 doğal bir kesme noktasıydı. Burada öyle bir nokta yok. Bu, kesmenin veriden değil karardan geldiği anlamına gelir ve kararın bedeli tabloda okunur.
Rank 2 yaklaşım 3.024 sayı yerine 554 sayı saklıyor — özgünün 0,183’ü — ve hatayı tabandan 0,5947 aşağı çekiyor. Rank 8’e çıkıldığında hata 0,7925’e iniyor ama saklanan sayı 2.144’e, yani özgünün 0,709’una çıkıyor. Rank 11’de hata sıfır ve saklama 2.939 sayı; özgün 3.024’ten yalnız 85 sayı az. Hatasız sıkıştırma bu tabloda pratikte yok, çünkü rank on birdir ve on iki sütunla arasındaki tek fark bölge göstergelerinin toplamıdır — önceki dersin on birinci yönde sıfıra inen hatası burada rank olarak adını buluyor.
Aynı Bütçeyle Ham Sütun Saklamak
Sayı adedi bir bütçedir ve bütçeyi harcamanın başka bir yolu vardır: ham sütunların bir kısmını olduğu gibi tutup kalanını ortalamayla kurmak. Bu, önceki kursun öznitelik seçimi konusunda ölçtüğü karara benzer ama burada ölçüt farklıdır — soru hangi sütunun ayırt ettiği değil, hangi sütunun tabloyu geri kurduğudur. Karşılaştırma anlamlı olsun diye tutulacak sütunlar rastgele seçilir ve üç çekiliş ortalanır.
def sutun_taban(r, tohum): rr, idx = uretec(tohum), list(range(n)) for i in range(n - 1, 0, -1): j = int(rr() * (i + 1)) idx[i], idx[j] = idx[j], idx[i] tut = set(idx[:r]) return sum(sum(z[j] * z[j] for j in range(n) if j not in tut) ** 0.5 for z in Z) / N print(f"{'r':>3} {'dusuk rank':>11} {'saklanan':>9} {'r ham sutun':>12} " f"{'saklanan':>9} {'fark':>8}") for r in (1, 2, 4, 6, 8, 11): st = sum(sutun_taban(r, TOHUM + 500 * (t + 1)) for t in range(3)) / 3 print(f"{r:>3} {hata(r):>11.4f} {24 + r * (N + n + 1):>9} {st:>12.4f} " f"{r * N + r:>9} {st - hata(r):>+8.4f}")
r dusuk rank saklanan r ham sutun saklanan fark 1 3.0129 289 3.2008 253 +0.1879 2 2.7464 554 3.0617 506 +0.3153 4 2.1363 1084 2.6787 1012 +0.5423 6 1.5054 1614 2.2730 1518 +0.7676 8 0.7925 2144 1.7588 2024 +0.9663 11 0.0000 2939 0.7857 2783 +0.7857
İki yol neredeyse aynı bütçeyi harcıyor: rank 2 için 554 sayı, iki ham sütun için 506. Fark 48 sayıdır, bütçenin yüzde onundan azı. Karşılığında alınan hata farkı rank 2’de 0,3153. Düşük ranklı yaklaşım kazanıyor, ama kazanç küçük — ve bu tablo için önemli bir bulgudur, çünkü boyut azaltmanın ham sütun saklamaya üstünlüğünün kendiliğinden olduğu varsayılır.
Üstünlük rank büyüdükçe açılıyor: 4’te 0,5423, 6’da 0,7676, 8’de 0,9663. Nedeni tekil değer listesinde duruyor. Düşük ranklı yaklaşım her rankta dizeyin o rankta taşınabilecek en iyi parçasını alır; ham sütun saklamak ise sütunları olduğu gibi alır ve sütunlar arasındaki ortak yapıyı hiç kullanmaz. Rank arttıkça bu ortak yapı birikir. Rank 11’de fark tersine dönmeye başlar (0,7857), çünkü rank 11 zaten hatasızdır ve karşı taraf tek bir sütunu atmanın hatasını taşır.
Karar bu iki tablodan okunur. Sıkıştırma amacıyla düşük ranklı yaklaşım kullanmak, hatayı tekil değerlerden önceden bilebilmek ve her sayıya karşılık en çok geri kurmayı almak demektir. Ama tablo dar ve rank yüksekse, kazanç ne saklamada ne hatada büyüktür — 3.024 sayının 554’e inmesi hatanın tabandan yalnız 0,5947 uzaklaşmasıyla ödenir.
Özet
- Tekil değer ayrışımı dizeyi satır yönleri, sütun yönleri ve tekil değerler olarak yazar; ilk r terimi tutmak düşük ranklı yaklaşımdır.
- Geri kurma hatası atılan tekil değerlerden okunur: küçük dizeyde rank 2’nin toplam hatası 0,6746 ve atılan tek tekil değer de 0,6746’dır.
- Tam ayrışım sıkıştırma değildir: küçük dizeyde rank 3 yaklaşım hatasızdır ama 36 sayı saklar, özgün dizey 30 sayıdır.
- Abone tablosunda taban çizgisi 3,3411; rank 2 yaklaşım 2,7464 verir ve 3.024 sayı yerine 554 sayı saklar. Rank 11 hatasızdır ve yalnız 85 sayı kazandırır.
- Aynı bütçeyle rastgele ham sütun saklamak rank 2’de 3,0617 verir; düşük ranklı yaklaşımın üstünlüğü orada 0,3153’tür ve ancak rank 8’de 0,9663’e çıkar.
Sonraki Adım
İki derste izdüşüm hep aynı biçimdeydi: her yeni sayı, eski sütunların ağırlıklı toplamıydı. Bu kısıt hatayı hesaplanabilir kıldı ve tekil değerlerden okunmasını sağladı, ama bir bedeli var — doğrular yalnız doğrulara gider. Noktalar bir düzlemde değil de kıvrılmış bir yüzeyde duruyorsa, ağırlıklı toplamla kurulan hiçbir izdüşüm o kıvrımı takip edemez ve komşu noktalar izdüşümde birbirinden uzağa düşer. Sonraki ders bu kısıtı kaldıran yaklaşımları ele alır: uzaklıkları değil komşulukları korumayı hedefleyen gömmeler. Ölçü de değişir, çünkü geri kurma hatası orada tanımsızdır — sorulacak soru, özgün uzayda en yakın komşuların kaçının gömmede de komşu kaldığıdır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.