Ders 05 / 11
Makine Öğrenmesi İş Akışı
Yedi adımlık akış üç geri dönüş üretir ve her dönüşün oynattığı sayı basılır. Beşinci adımdaki kapı tabana göre farkı 0,0500 eşiğiyle sınar: üç sütunla kurulan model 0,0318 verip kapıda kalır, dokuz sütunla 0,1061 verip geçer. Altıncı adımda model 1.260 abonenin 240'ını işaretler, günlük kapasite 40 ziyarettir ve liste altı güne yayılır; kısıt problemi sınıflandırmadan sıralamaya çevirir, sıralama ilk 40 ziyarette 30 kaçak bulur, rastgele sıra 14. Yedinci adımda ölçüm politikası değişir, etiket değişmediği hâlde aynı model 23'e düşer ve kayan veriyle yeniden kurulduğunda 30'a döner. Yedi adımlık akış toplam 22 adım ziyaretiyle tamamlanır.
İçindekiler
Dört ders bir modelin nasıl kurulduğunu gösterdi: hazır bir tablo, hazır bir öznitelik kümesi, hazır bir ayrım ve tek bir ölçüm. Gerçek bir işte hiçbiri hazır gelmez. Problem tanımı ölçümden sonra değişir, öznitelik kümesi değerlendirmeden sonra genişler ve akış hiçbir zaman baştan sona bir kez akmaz.
Bu ders akışı yedi adım olarak kurar ve adımları değil geri dönüşleri sayar. Veri Analitiğine Giriş kursundaki analiz iş akışı dersi de dönüşleri saymıştı; orada dönüşün nedeni bir kararın ait olduğu adımdan sonra görülmesiydi. Burada dönüşü tetikleyen şey bir karar değil bir ölçümdür: akış, bir sayı eşiğin altında kaldığı için geri döner.
- MK26. Akış yedi adımdır: problem tanımı, veri hazırlama, öznitelik seçimi, model kurma, değerlendirme, dağıtım, izleme. Ölçülen şey adım sayısı değil geri dönüş sayısıdır.
- MK27. Kapı, akışın ilerleme kararını bir sayıya bağlayan denetimdir. Kapının eşiği ölçümden önce yazılır; sonra yazılırsa eşik bir karar değil bir gerekçe olur.
- MK28. Bu koşumda dönüşün üç ayrı kaynağı vardır: ölçümün eşiği tutturamaması, dağıtım kısıtı ve izlemede verinin kayması.
- MK29. Dağıtım kısıtı problem tanımını değiştirebilir. Sınıflandırmanın çıktısı bir kümedir, sıralamanınki bir kuyruktur; sınırlı kapasiteyle çalışan bir ekibin istediği şey kuyruktur.
- MK30. İzleme, model hiç değişmediği hâlde sayının değişebildiği tek adımdır. Kayan şey modelin kendisi değil, modele gelen veridir.
- MK31. Dağıtımdan sonra modelin ürettiği karara çıkarım (inference) denir. Terim, Görselleştirme ve Raporlama kursunda okuyucunun bir grafikten çıkardığı sonuç anlamında kullanılan çıkarımdan ayrıdır: burada çıkarımı yapan okuyucu değil modeldir.
Kurgu Kümenin Yeniden Kurulması
# kurulum.py — 01. dersin kurgu kumesi ayni tohumla yeniden kurulur: okuma # tablosu, abone ozeti, kurgu etiket, egitim / ayrilmis ayrimi ve agac ogrenici. 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)] OZNITELIK = ["ortalama", "kisi_basi", "dusus", "sifir_okuma", "okuma_sayisi", "memnuniyet", "hane_kisi", "en_yuksek", "en_dusuk"] 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 _ab, _el, _seri = [], [], {} 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} (_el if r() < 0.046 else _ab).append(k) _gecerli = {a["abone_no"] for a in _ab} for k in _ab + _el: 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: _seri.setdefault(k["abone_no"], []).append(t) r() ABONE = [] for k in _ab: t = _seri.get(k["abone_no"]) if not t: continue ort = sum(t) / len(t) a = {"abone_no": k["abone_no"], "bolge": k["bolge"], "seri": t, "hane_kisi": k["hane_kisi"], "memnuniyet": k["memnuniyet"], "okuma_sayisi": len(t), "ortalama": ort, "en_yuksek": max(t), "en_dusuk": min(t), "sifir_okuma": sum(1 for v in t if v == 0), "kisi_basi": ort / max(1, k["hane_kisi"]), "dusus": (t[0] - t[-1]) / t[0] if len(t) > 1 and t[0] > 0 else 0.0} r = uretec(TOHUM + 31000 + a["abone_no"]) a["suphe"] = 1 if (1.30 * a["sifir_okuma"] + 1.25 * (a["dusus"] > 0.45) + 1.05 * (a["kisi_basi"] > 12.0) + 0.65 * (a["okuma_sayisi"] < 3) + 0.45 * (a["memnuniyet"] <= 2) - 1.55 + (r() + r() - 1.0) * 1.1) > 0 else 0 ABONE.append(a) r = uretec(TOHUM + 90001) EGITIM, AYRILMIS = [], [] for a in ABONE: (EGITIM if r() < 0.70 else AYRILMIS).append(a) poz = lambda k: sum(a["suphe"] for a in k) dogruluk = lambda f, k: sum(1 for a in k if f(a) == a["suphe"]) / len(k) _saf = lambda k: 2 * (poz(k) / len(k)) * (1 - poz(k) / len(k)) if k else 0.0 def ogren(k, derinlik=3, en_az=40): """01. dersin acgozlu karar agaci: bolme olcutu ve durma kurali orada.""" en, secim = _saf(k) * len(k), None if derinlik and len(k) >= en_az: for oz in OZNITELIK: for e in sorted({a[oz] for a in k})[1:]: sol = [a for a in k if a[oz] < e] sag = [a for a in k if a[oz] >= e] m = _saf(sol) * len(sol) + _saf(sag) * len(sag) if m < en - 1e-9: en, secim = m, (oz, e, sol, sag) if secim is None: return 1 if 2 * poz(k) > len(k) else 0 s, g = ogren(secim[2], derinlik - 1, en_az), ogren(secim[3], derinlik - 1, en_az) return s if s == g else (secim[0], secim[1], s, g) def uygula(d, a): while isinstance(d, tuple): d = d[2] if a[d[0]] < d[1] else d[3] return d print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, {len(EGITIM)} egitim, " f"{len(AYRILMIS)} ayrilmis, {poz(ABONE)} supheli")
kurgu kume (tohum 20260218): 1260 abone, 883 egitim, 377 ayrilmis, 327 supheli
Yedi Adım ve Birinci Kapı
Akış birinci adımda tanımlanır: soru “bu abone şüpheli mi”, ölçü doğruluk, taban çizgisi en sık sınıf. Beşinci adımdaki kapının eşiği de burada yazılır: model, ayrılmış kümede tabanı en az 0,0500 geçmelidir. Bu sayı bir mühendislik kararıdır ve ölçümden önce yazıldığı için bir karardır; ölçümden sonra yazılsaydı sonucu meşrulaştıran bir gerekçe olurdu.
İkinci adımda veri hazırlanır. Birinci geçişte okuma tablosunun özetleri henüz hazır değildir, bu yüzden üçüncü adım yalnız abone kaydından gelen üç sütunu seçer.
# akis.py — yedi adim ve iki kapi. Kapilar sayiya bakar: besinci adimdaki kapi # tabana gore farki, altincidaki gunluk saha kapasitesini olcer. import statistics from collections import Counter ADIM = ["1 problem tanimi", "2 veri hazirlama", "3 oznitelik secimi", "4 model kurma", "5 degerlendirme", "6 dagitim", "7 izleme"] KABUL_FARK, KAPASITE = 0.05, 40 DONUS, TAM = [], OZNITELIK[:] KAYIT = ["hane_kisi", "memnuniyet", "okuma_sayisi"] en_sik = Counter(a["suphe"] for a in EGITIM).most_common(1)[0][0] TABAN_E, TABAN_A = dogruluk(lambda a: en_sik, EGITIM), dogruluk(lambda a: en_sik, AYRILMIS) def agacla(oz, kume): global OZNITELIK OZNITELIK = oz d = ogren(kume) OZNITELIK = TAM return d E = [8, 16, 11, 11, 11, 11, 22] y = lambda h: str(h[0]).ljust(E[0]) + str(h[1]).ljust(E[1]) + "".join( str(v).rjust(E[i + 2]) for i, v in enumerate(h[2:6])) + " " + str(h[6]) print(y(["gecis", "oznitelik", "taban", "egitimde", "ayrilmista", "fark", "kapi"])) AGAC = {} for gecis, oz in ((1, KAYIT), (2, TAM)): d = AGAC[gecis] = agacla(oz, EGITIM) ic, dis = dogruluk(lambda a: uygula(d, a), EGITIM), dogruluk( lambda a: uygula(d, a), AYRILMIS) fark = dis - TABAN_A gecti = fark >= KABUL_FARK print(y([gecis, f"{len(oz)} sutun", f"{TABAN_A:.4f}", f"{ic:.4f}", f"{dis:.4f}", f"{fark:+.4f}", "gecti" if gecti else f"kapali, esik {KABUL_FARK:.2f}"])) if not gecti: DONUS.append([ADIM[4], ADIM[2], "fark esigin altinda", f"{fark:+.4f}", None]) else: DONUS[-1][4] = f"{fark:+.4f}" isaret = sum(1 for a in ABONE if uygula(AGAC[2], a)) print(f"\n6. adim: model {len(ABONE)} abonenin {isaret} tanesini isaretliyor; " f"gunluk kapasite {KAPASITE} ziyaret, yani liste " f"{-(-isaret // KAPASITE)} gune yayiliyor ve icinde sira yok") DONUS.append([ADIM[5], ADIM[0], "kapasiteye sigmiyor", f"{isaret} isaret", None])
gecis oznitelik taban egitimde ayrilmista fark kapi 1 3 sutun 0.7533 0.7939 0.7851 +0.0318 kapali, esik 0.05 2 9 sutun 0.7533 0.8709 0.8594 +0.1061 gecti 6. adim: model 1260 abonenin 240 tanesini isaretliyor; gunluk kapasite 40 ziyaret, yani liste 6 gune yayiliyor ve icinde sira yok
Birinci geçiş kapıda kaldı: 0,0318 eşiğin altındadır. Akış beşinci adımdan üçüncü adıma döner ve öznitelik kümesi okuma tablosunun özetleriyle dokuz sütuna çıkar. İkinci geçişte fark 0,1061’dir ve kapı açılır. Dönüşün oynattığı sayı budur: 0,0318 yerine 0,1061.
Altıncı adımda ikinci kapı devreye giriyor ve model başarımını değil işin kısıtını ölçüyor. Model 1.260 abonenin 240’ını işaretliyor. Günlük kapasite 40 ziyarettir, yani liste altı güne yayılır ve sınıflandırma çıktısı liste içinde kimin önce gezileceğini söylemez. Model kapıyı başarımla geçti, kısıtla geçemedi.
Kısıt Problemi Değiştirir, İzleme Veriyi
Altıncı adımdan birinci adıma dönülür. Bu, akışın en uzun dönüşüdür ve modeli değil soruyu değiştirir: karar isteyen bir soru yerine sıra isteyen bir soru yazılır. Ölçü de değişir — doğruluk yerine ilk 40 ziyarette bulunan kaçak sayısı — ve tabanı da yeniden seçilir: rastgele sıra.
Yedinci adımda model sahadadır ve izlenir. İzlemenin ölçtüğü şey modelin kendisi değildir, çünkü model değişmemektedir. Değişen şey modele gelen veridir: şebeke okuma politikasını değiştirir, sıfır okumalar kestirimle doldurulur ve eksik dönemler tamamlanır. Aboneler aynıdır, gerçek kaçak durumu aynıdır, yalnız tabloya yazılma biçimi değişmiştir.
# siralama_ve_izleme.py — problem yeniden tanimlanir: karar degil sira istenir. # Dagitimdan sonra olcum politikasi degisir ve ayni model yeniden olculur. r = uretec(TOHUM + 7205) TOPLULUK = [ogren([EGITIM[int(r() * len(EGITIM))] for _ in EGITIM]) for _ in range(9)] r = uretec(TOHUM + 7206) kura = {a["abone_no"]: r() for a in ABONE} ilk = lambda f, s: poz(sorted(s, key=f)[:KAPASITE]) sira = lambda T: (lambda a: (-sum(uygula(d, a) for d in T), a["abone_no"])) rastgele = lambda a: kura[a["abone_no"]] def kayan(a): """Okuma politikasi degisti: sifir okumalar kestirimle dolduruluyor, eksik donemler tamamlaniyor. Gercek kacak durumu, yani etiket, degismiyor.""" dolu = [v for v in a["seri"] if v > 0] tem = round(statistics.fmean(dolu), 2) if dolu else 0.0 t = [v if v > 0 else tem for v in a["seri"]] + [tem] * (3 - len(a["seri"])) ort = sum(t) / len(t) return {**a, "seri": t, "okuma_sayisi": 3, "ortalama": ort, "en_yuksek": max(t), "en_dusuk": min(t), "sifir_okuma": sum(1 for v in t if v == 0), "kisi_basi": ort / max(1, a["hane_kisi"]), "dusus": (t[0] - t[-1]) / t[0] if t[0] > 0 else 0.0} KAYAN_E, KAYAN_A = [kayan(a) for a in EGITIM], [kayan(a) for a in AYRILMIS] r = uretec(TOHUM + 7305) YENI = [ogren([KAYAN_E[int(r() * len(KAYAN_E))] for _ in KAYAN_E]) for _ in range(9)] D = [30, 14, 12, 12] z = lambda h: str(h[0]).ljust(D[0]) + "".join(str(v).rjust(D[i + 1]) for i, v in enumerate(h[1:])) print(z([f"ilk {KAPASITE} ziyarette kacak", "veri", "egitimde", "ayrilmista"])) print(z(["taban: rastgele sira", "eski", ilk(rastgele, EGITIM), ilk(rastgele, AYRILMIS)])) print(z(["model: dokuz agacli sira", "eski", ilk(sira(TOPLULUK), EGITIM), ilk(sira(TOPLULUK), AYRILMIS)])) print(z(["taban: rastgele sira", "kayan", ilk(rastgele, KAYAN_E), ilk(rastgele, KAYAN_A)])) print(z(["ayni model", "kayan", ilk(sira(TOPLULUK), KAYAN_E), ilk(sira(TOPLULUK), KAYAN_A)])) print(z(["kayan veriyle kurulan model", "kayan", ilk(sira(YENI), KAYAN_E), ilk(sira(YENI), KAYAN_A)])) print(f"\netiket degismedi: eskide {poz(AYRILMIS)}, kayanda {poz(KAYAN_A)} supheli") print(f"bozulan iki oznitelik: sifir okuma toplami " f"{sum(a['sifir_okuma'] for a in AYRILMIS)} -> {sum(a['sifir_okuma'] for a in KAYAN_A)}, " f"eksik donemli abone {sum(1 for a in AYRILMIS if a['okuma_sayisi'] < 3)} -> " f"{sum(1 for a in KAYAN_A if a['okuma_sayisi'] < 3)}") DONUS[1][4] = f"ilk {KAPASITE}'ta {ilk(sira(TOPLULUK), AYRILMIS)} kacak" DONUS.append([ADIM[6], ADIM[1], "olcum politikasi degisti", f"{ilk(sira(TOPLULUK), KAYAN_A)} kacak", f"{ilk(sira(YENI), KAYAN_A)} kacak"])
ilk 40 ziyarette kacak veri egitimde ayrilmista taban: rastgele sira eski 10 14 model: dokuz agacli sira eski 30 30 taban: rastgele sira kayan 10 14 ayni model kayan 33 23 kayan veriyle kurulan model kayan 39 30 etiket degismedi: eskide 93, kayanda 93 supheli bozulan iki oznitelik: sifir okuma toplami 39 -> 3, eksik donemli abone 117 -> 0
Aynı model, aynı aboneler, aynı etiketler ve düşen bir sayı: ilk 40 ziyarette 30 kaçak yerine 23. Rastgele sıranın tabanı 14’te sabit kaldığı için düşüş modelindir, sorunun zorlaşması değildir. Nedeni son satırda yazılı: modelin dayandığı iki öznitelik silinmiştir. Sıfır okuma toplamı 39’dan 3’e, eksik dönemli abone sayısı 117’den 0’a inmiştir. Model bu iki sütunun taşıdığı bilgiyle karar veriyordu ve o bilgi artık tabloya yazılmıyor.
Yedinci adımdan ikinci adıma dönülür. Veri yeni politikaya göre yeniden hazırlanır, model kayan veriyle yeniden kurulur ve sayı 30’a döner. Kayıp kapanmıştır, ama kapanma bedeli bir dönüştür ve dönüş ancak izleme adımı varsa görülür. İzleme olmasaydı sahadaki liste yedi kaçak eksik üretmeye devam eder ve bunu kimse fark etmezdi.
Dönüşlerin Muhasebesi
# donusler.py — akisin olcusu adim sayisi degil geri donus sayisidir. F = [18, 20, 28, 16, 16] w = lambda h: "".join(str(v).ljust(F[i]) for i, v in enumerate(h)) print(w(["nereden", "nereye", "sebep", "donus oncesi", "donus sonrasi"])) for d in DONUS: print(w(d)) print(f"\n{len(ADIM)} adimlik akis {len(DONUS)} geri donus uretti; " f"toplam adim ziyareti {sum(int(x[0][0]) - int(x[1][0]) + 1 for x in DONUS) + len(ADIM)}")
nereden nereye sebep donus oncesi donus sonrasi 5 degerlendirme 3 oznitelik secimi fark esigin altinda +0.0318 +0.1061 6 dagitim 1 problem tanimi kapasiteye sigmiyor 240 isaret ilk 40'ta 30 kacak 7 izleme 2 veri hazirlama olcum politikasi degisti 23 kacak 30 kacak 7 adimlik akis 3 geri donus uretti; toplam adim ziyareti 22
Üç dönüşün üçü de farklı bir adımdan çıkıyor ve farklı bir adıma iniyor. Beşinci adımdan üçüncüye dönüş kısadır ve üç adım yeniden ziyaret edilir; altıncıdan birinciye dönüş altı adımı, yedinciden ikinciye dönüş yine altı adımı yeniden ziyaret ettirir. Doğrusal okunduğunda yedi adımlık olan akış 22 adım ziyaretiyle tamamlanmıştır, yani her adım ortalama 3,1 kez ziyaret edilmiştir.
Muhasebenin kendisi de bir karardır. Burada bir dönüş, hedef adımdan çıkış adımına kadarki bütün adımların yeniden yürütülmesi sayılmıştır. Bazı adımların gerçekten tekrarlanması gerekmeyebilir — altıncıdan birinciye dönüşte veri hazırlama değişmemiştir — ve o durumda sayı daha küçük çıkardı. Hangi muhasebeyle üretildiği yazılmadan 22 okunamaz.
Dönüş sayısı bir kusur ölçüsü değildir. Sıfır dönüşlü bir akış, kapılarının hiçbir şeyi sınamadığı bir akıştır; birinci geçişte kapı olmasaydı 0,0318’lik bir model sahaya çıkardı ve kimse bunu ölçmemiş olurdu. Dönüş, kapının çalıştığının kanıtıdır.
Özet
- Akış yedi adımdır ve doğrusal değildir; bu koşumda üç geri dönüş üretmiş, 22 adım ziyaretiyle tamamlanmıştır.
- Beşinci adımdaki kapı tabana göre farkı 0,0500 eşiğiyle sınar: üç sütunlu model 0,0318 verip kapıda kalır, dokuz sütunlu model 0,1061 verip geçer.
- Altıncı adımdaki kapı başarımı değil kısıtı ölçer: model 240 abone işaretler, günlük kapasite 40’tır ve kısıt problemi sınıflandırmadan sıralamaya çevirir; sıralama ilk 40 ziyarette 30 kaçak bulur, rastgele sıra 14.
- Yedinci adımda model değişmeden sayı düşer: ölçüm politikası değişince aynı model 23 kaçak bulur, çünkü dayandığı iki öznitelik silinmiştir; kayan veriyle yeniden kurulunca 30’a döner.
- Dönüş sayısı bir kusur ölçüsü değil, kapıların çalıştığının kanıtıdır; sıfır dönüş kapıların hiçbir şeyi sınamadığı anlamına gelir.
Sonraki Adım
Bu ders akışı tek bir masadan yürüttü: bir kişi soruyu yazdı, öznitelikleri seçti, modeli kurdu, eşiği koydu ve sahayı izledi. Gerçekte bu adımlar farklı iş tanımları arasında bölünür ve bölünme yalnız işi paylaştırmakla kalmaz, teslim edilen şeyi de değiştirir. Veri Analitiğine Giriş kursu üç analist rolünü kabul ölçütleriyle ayırmıştı; sonraki ders aynı ayrımı makine öğrenmesi tarafında yapar. Aynı kaçak problemi üç rolde üç ayrı çıktıya dönüşür ve üçü üç ayrı taban çizgisi seçer: bir rol için taban sahanın bugünkü yordamı, bir diğeri için hâlihazırda çalışan model, üçüncüsü için modelsiz kurulan sistemin kendisidir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.