{
  "cells": [
    {
      "cell_type": "markdown",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": "# Hafta 7: Üretim Ortamında Model İzleme ve Sürekli Teslimat (CD)\n\n**Dersin Hedefleri:**\n1.  Bir makine öğrenmesi modelinin performansının zamanla neden düştüğünü (model degradation) anlamak.\n2.  Veri Kayması (Data Drift) ve Kavram Kayması (Concept Drift) arasındaki farkı kavramak.\n3.  Üretimdeki bir modelin hem operasyonel hem de performans metriklerini izlemek için stratejiler öğrenmek.\n4.  Veri kaymasını tespit etmek için istatistiksel yöntemler uygulamak.\n5.  Sürekli Teslimat/Dağıtım (Continuous Delivery/Deployment) kavramını ve MLOps döngüsünü nasıl tamamladığını anlamak.\n\n## 1. Neden Modeller Zamanla \"Eskir\"?\n\nBir modeli eğitip dağıttığınızda, o model, eğitim verisinin temsil ettiği \"dünyanın anlık bir fotoğrafı\" üzerine kuruludur. Ancak dünya statik değildir.\n\n- **Veri Kayması (Data Drift):** Üretim ortamına gelen verinin istatistiksel özellikleri (örn: ortalama, dağılım), modelin eğitildiği veriden zamanla farklılaşmaya başlar. **Örnek:** Ekonomik bir kriz sonrası, insanların ortalama geliri düşebilir. Modeliniz \"gelir\" özelliğine dayanıyorsa, performansı düşecektir. Modelin kendisi hala doğrudur, ancak girdi verisi değişmiştir.\n- **Kavram Kayması (Concept Drift):** Verideki özellikler ile hedef değişken arasındaki temel ilişki değişir. Bu daha nadir ama daha ciddi bir sorundur. **Örnek:** Bir spam tespit modelinde, \"ücretsiz\" kelimesi başlangıçta güçlü bir spam göstergesiyken, zamanla spam gönderenlerin yeni taktikler geliştirmesiyle bu kelimenin önemi azalabilir. Aynı girdi, artık farklı bir anlama gelmektedir.\n\nBu nedenlerle, dağıtılan bir modeli \"kur ve unut\" yaklaşımıyla bırakmak, kaçınılmaz olarak performans düşüşüne ve yanlış kararlara yol açar.\n\n## 2. İzlenmesi Gerekenler Nelerdir?\n\n### a) Operasyonel Metrikler (Sistem Sağlığı)\nBunlar, model API'mizin bir yazılım olarak ne kadar sağlıklı çalıştığını gösterir.\n- **Gecikme Süresi (Latency):** Bir tahmin isteğine cevap vermek ne kadar sürüyor?\n- **Trafik (Throughput):** Saniyede kaç istek karşılanıyor?\n- **Hata Oranı (Error Rate):** İsteklerin yüzde kaçı 500 gibi sunucu hatalarıyla sonuçlanıyor?\n- **Kaynak Kullanımı:** CPU, bellek, disk kullanımı ne durumda?\n\n### b) Model Performans Metrikleri (Tahmin Kalitesi)\nBunlar, modelin tahminlerinin ne kadar doğru olduğunu gösterir. Bunun için \"ground truth\" (gerçek etiketler) gereklidir, ki bu her zaman anında mevcut olmayabilir.\n- **Accuracy, Precision, Recall, F1-Score, ROC AUC** gibi metriklerin zaman içindeki değişimi.\n\n### c) Veri Kayması Metrikleri (Veri Sağlığı)\nGround truth olmadığında bile, modelin performansının düşebileceğine dair erken bir uyarı sistemi olarak çalışırlar.\n- **Girdi Veri Dağılımı:** Üretimdeki verinin sayısal özelliklerinin (ortalama, standart sapma, min, max) eğitim verisinden ne kadar saptığı.\n- **Kategorik Veri Dağılımı:** Kategorik özelliklerin frekanslarının değişip değişmediği.\n\n## 3. Pratik Uygulama: Veri Kaymasını Tespit Etme\n\nBu bölümde, bir modelin eğitildiği \"referans\" veri seti ile zamanla gelen \"üretim\" veri seti arasında bir kayma olup olmadığını istatistiksel olarak nasıl tespit edebileceğimizi göreceğiz.\n\n**Yöntem:** Sayısal iki örneklemin (referans ve üretim) aynı dağılımdan gelip gelmediğini test eden **Kolmogorov-Smirnov (K-S) testini** kullanacağız.\n- **Null Hipotezi (H0):** İki örneklem aynı dağılımdan gelmektedir (kayma yok).\n- **Test Sonucu:** Testin p-değeri, belirlediğimiz bir anlamlılık seviyesinden (örn: 0.05) küçükse, H0 hipotezini reddederiz ve **\"İki dağılım arasında istatistiksel olarak anlamlı bir fark vardır, yani veri kayması tespit edilmiştir\"** deriz.\n\n**Kurulum:**\n```bash\npip install scipy\n```"
    },
    {
      "cell_type": "markdown",
      "source": "from scipy.stats import ks_2samp\n\ndef check_drift(reference_series, production_series, feature_name, alpha=0.05):\n    \"\"\"\n    K-S testi kullanarak veri kaymasını tespit eder.\n    \n    Parameters:\n    -----------\n    reference_series : pd.Series\n        Referans (eğitim) verisi\n    production_series : pd.Series\n        Üretim verisi\n    feature_name : str\n        Özellik adı\n    alpha : float\n        Anlamlılık seviyesi (varsayılan: 0.05)\n    \n    Returns:\n    --------\n    bool : Kayma tespit edildiyse True, edilmediyse False\n    \"\"\"\n    ks_statistic, p_value = ks_2samp(reference_series, production_series)\n    \n    print(f\"\\n{'='*60}\")\n    print(f\"  {feature_name} için Veri Kayması Analizi\")\n    print(f\"{'='*60}\")\n    print(f\"K-S İstatistiği: {ks_statistic:.4f}\")\n    print(f\"P-Değeri:        {p_value:.4f}\")\n    print(f\"Anlamlılık:      α = {alpha}\")\n    print(f\"{'-'*60}\")\n    \n    if p_value < alpha:\n        print(f\"✗ SONUÇ: VERİ KAYMASI TESPİT EDİLDİ (p={p_value:.4f} < {alpha})\")\n        print(f\"  Null hipotez reddedildi.\")\n        print(f\"  İki dağılım istatistiksel olarak farklıdır.\")\n        return True\n    else:\n        print(f\"✓ SONUÇ: Anlamlı bir kayma YOK (p={p_value:.4f} ≥ {alpha})\")\n        print(f\"  Null hipotez reddedilemedi.\")\n        print(f\"  İki dağılım benzerdir.\")\n        return False\n\n# Testleri çalıştır\nprint(\"TEST 1: Normal Üretim Verisi (Kayma Beklenmez)\")\ncheck_drift(reference_data['temperature'], production_data_ok['temperature'], \n            'Sıcaklık (Normal Durum)')\n\nprint(\"\\n\\nTEST 2: Kayma Olan Üretim Verisi (Kayma Beklenir)\")\ncheck_drift(reference_data['temperature'], production_data_drifted['temperature'], \n            'Sıcaklık (Kayma Durumu)')",
      "metadata": {},
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": "## 4. Sürekli Teslimat/Dağıtım (CI/CD)\n\nCI (Sürekli Entegrasyon) kodun kalitesini kontrol eder. CD ise bu kaliteli kodun (veya modelin) üretim ortamına otomatik olarak dağıtılmasını sağlar.\n\n**Basitleştirilmiş bir MLOps CD Pipeline'ı:**\n\n1.  Bir veri bilimci, yeni verilerle veya daha iyi bir teknikle eğittiği yeni bir modeli `MLflow`'a kaydeder.\n2.  Bu yeni model, bir \"hazırlık\" (staging) ortamında bir dizi otomatik teste tabi tutulur:\n    *   Modelin performansı, mevcut üretimdeki modelden daha mı iyi?\n    *   Modelin tahmin gecikmesi kabul edilebilir sınırlar içinde mi?\n    *   Model, bilinen kritik veri örnekleri (edge cases) için mantıklı tahminler üretiyor mu?\n3.  Tüm testler başarılı olursa, bir yetkilinin onayıyla (Sürekli Teslimat) veya tamamen otomatik olarak (Sürekli Dağıtım), yeni model, üretimdeki eski modelin yerini alır.\n\nBu döngü, MLOps'un son halkasıdır ve ML sistemlerinin sürekli olarak öğrenmesini ve iyileşmesini sağlar.",
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": "### Alıştırma Özeti\n\n**Öğrenilen Konular:**\n\n1. **Veri Analizi Otomasyonu:**\n   - `select_dtypes()` ile veri tiplerini filtreleme\n   - DataFrame iteration ile dinamik analiz\n   - Liste comprehension ile veri yapıları oluşturma\n\n2. **İstatistiksel Test Uygulaması:**\n   - K-S testini programatik olarak uygulama\n   - P-değerlerini yorumlama\n   - Çoklu test senaryolarını otomatikleştirme\n\n3. **Veri Görselleştirme:**\n   - Çoklu subplot'lar ile dashboard oluşturma\n   - Koşullu renklendirme (drift detected → red, else → green)\n   - Bar charts, pie charts ile özet bilgi sunma\n\n4. **Production-Ready Kod:**\n   - Kapsamlı docstring yazımı\n   - Error handling (sütun kontrolü)\n   - Okunabilir output formatı\n\n**Gerçek Dünya Kullanımı:**\nBu rapor günlük/haftalık cron job ile çalıştırılarak:\n- Email ile takımlara gönderilebilir\n- Dashboard'a yüklenebilir\n- Otomatik uyarı sistemlerine bağlanabilir\n- Model yeniden eğitim pipeline'ını tetikleyebilir",
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": "fig, axes = plt.subplots(2, 2, figsize=(16, 10))\n\n# Grafik 1: P-değerleri\nax1 = axes[0, 0]\ncolors = ['red' if x else 'green' for x in monitoring_report['drift_detected']]\nax1.barh(monitoring_report['feature_name'], monitoring_report['ks_p_value'], color=colors, alpha=0.7)\nax1.axvline(x=0.05, color='black', linestyle='--', linewidth=2, label='α = 0.05 (Eşik)')\nax1.set_xlabel('P-Değeri', fontsize=12)\nax1.set_ylabel('Özellik', fontsize=12)\nax1.set_title('K-S Testi P-Değerleri', fontsize=14, fontweight='bold')\nax1.legend()\nax1.grid(alpha=0.3)\n\n# Grafik 2: Ortalama Farkları (%)\nax2 = axes[0, 1]\ncolors = ['red' if x else 'green' for x in monitoring_report['drift_detected']]\nax2.barh(monitoring_report['feature_name'], monitoring_report['mean_diff_pct'], color=colors, alpha=0.7)\nax2.axvline(x=0, color='black', linestyle='-', linewidth=1)\nax2.set_xlabel('Ortalama Farkı (%)', fontsize=12)\nax2.set_ylabel('Özellik', fontsize=12)\nax2.set_title('Referans vs Üretim: Ortalama Farkı', fontsize=14, fontweight='bold')\nax2.grid(alpha=0.3)\n\n# Grafik 3: K-S İstatistiği\nax3 = axes[1, 0]\ncolors = ['red' if x else 'green' for x in monitoring_report['drift_detected']]\nax3.barh(monitoring_report['feature_name'], monitoring_report['ks_statistic'], color=colors, alpha=0.7)\nax3.set_xlabel('K-S İstatistiği', fontsize=12)\nax3.set_ylabel('Özellik', fontsize=12)\nax3.set_title('Kolmogorov-Smirnov İstatistikleri', fontsize=14, fontweight='bold')\nax3.grid(alpha=0.3)\n\n# Grafik 4: Kayma Durumu (Pie Chart)\nax4 = axes[1, 1]\ndrift_summary = monitoring_report['drift_detected'].value_counts()\ncolors_pie = ['#ff6b6b', '#51cf66']\nlabels = ['Kayma Tespit Edildi', 'Kayma Yok']\nif True in drift_summary.index and False in drift_summary.index:\n    ax4.pie([drift_summary[True], drift_summary[False]], \n            labels=labels, autopct='%1.1f%%', colors=colors_pie, startangle=90)\nelif True in drift_summary.index:\n    ax4.pie([drift_summary[True]], labels=['Kayma Tespit Edildi'], \n            autopct='%1.1f%%', colors=['#ff6b6b'], startangle=90)\nelse:\n    ax4.pie([drift_summary[False]], labels=['Kayma Yok'], \n            autopct='%1.1f%%', colors=['#51cf66'], startangle=90)\nax4.set_title('Genel Kayma Durumu', fontsize=14, fontweight='bold')\n\nplt.tight_layout()\nplt.show()",
      "metadata": {},
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": "### Adım 4: Görsel Rapor Oluşturma\n\nİzleme raporunu görselleştirerek daha anlaşılır hale getirelim.",
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": "print(\"=\"*80)\nprint(\" \" * 25 + \"VERİ SAĞLIĞI İZLEME RAPORU\")\nprint(\"=\"*80)\nprint(f\"Referans Veri Boyutu: {len(reference_data)}\")\nprint(f\"Üretim Veri Boyutu:   {len(production_data_drifted)}\")\nprint(f\"Anlamlılık Seviyesi:  α = 0.05\")\nprint(\"=\"*80)\n\n# Raporu göster\ndisplay(monitoring_report)\n\n# Özet istatistikler\nprint(\"\\n\" + \"=\"*80)\nprint(\" \" * 30 + \"ÖZET\")\nprint(\"=\"*80)\ndrift_count = monitoring_report['drift_detected'].sum()\ntotal_features = len(monitoring_report)\nprint(f\"Toplam Özellik Sayısı:        {total_features}\")\nprint(f\"Kayma Tespit Edilen Özellik:  {drift_count}\")\nprint(f\"Kayma Yüzdesi:                {(drift_count/total_features)*100:.1f}%\")\n\nif drift_count > 0:\n    print(f\"\\n⚠️  UYARI: {drift_count} özellikte veri kayması tespit edildi!\")\n    print(\"   Modelin performansı etkilenebilir. Aşağıdaki aksiyonlar önerilir:\")\n    print(\"   1. Modeli yeni verilerle yeniden eğitin\")\n    print(\"   2. Özellik mühendisliği stratejisini gözden geçirin\")\n    print(\"   3. Veri toplama sürecini inceleyin\")\nelse:\n    print(\"\\n✓ Tüm özellikler normal dağılım aralığında.\")",
      "metadata": {},
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": "### Adım 3: Raporu Görüntüleme ve Yorumlama",
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": "def generate_monitoring_report(ref_df, prod_df, alpha=0.05):\n    \"\"\"\n    Referans ve üretim veri setleri arasında veri kaymasını tespit eden rapor oluşturur.\n    \"\"\"\n    report_data = []\n    \n    # 1. Sadece sayısal sütunları al\n    numeric_cols = ref_df.select_dtypes(include=[np.number]).columns\n    \n    # 2. Her sayısal sütun için analiz yap\n    for col in numeric_cols:\n        # Sütun her iki veri setinde de var mı kontrol et\n        if col not in prod_df.columns:\n            print(f\"Uyarı: '{col}' sütunu üretim verisinde bulunamadı. Atlanıyor...\")\n            continue\n        \n        # İstatistikleri hesapla\n        ref_mean = ref_df[col].mean()\n        prod_mean = prod_df[col].mean()\n        mean_diff = prod_mean - ref_mean\n        mean_diff_pct = (mean_diff / ref_mean) * 100 if ref_mean != 0 else np.inf\n        \n        # K-S testi uygula\n        ks_stat, p_value = ks_2samp(ref_df[col], prod_df[col])\n        drift_detected = p_value < alpha\n        \n        # Rapor satırını oluştur\n        report_data.append({\n            \"feature_name\": col,\n            \"reference_mean\": ref_mean,\n            \"production_mean\": prod_mean,\n            \"mean_diff\": mean_diff,\n            \"mean_diff_pct\": mean_diff_pct,\n            \"ks_statistic\": ks_stat,\n            \"ks_p_value\": p_value,\n            \"drift_detected\": drift_detected\n        })\n    \n    # 3. DataFrame olarak döndür\n    report_df = pd.DataFrame(report_data)\n    \n    # 4. Okunabilirlik için sırala (kayma olanlar önce)\n    report_df = report_df.sort_values('drift_detected', ascending=False)\n    \n    return report_df\n\n# Fonksiyonu test et\nprint(\"İzleme Raporu Oluşturuluyor...\")\nmonitoring_report = generate_monitoring_report(reference_data, production_data_drifted)\nprint(\"\\n✓ Rapor oluşturuldu!\")",
      "metadata": {},
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": "### Adım 2: Fonksiyon İmplementasyonu\n\nŞimdi fonksiyonu adım adım implemente edelim:",
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": "def generate_monitoring_report(ref_df, prod_df, alpha=0.05):\n    \"\"\"\n    Referans ve üretim veri setleri arasında veri kaymasını tespit eden rapor oluşturur.\n    \n    Parameters:\n    -----------\n    ref_df : pd.DataFrame\n        Referans (eğitim) veri seti\n    prod_df : pd.DataFrame\n        Üretim veri seti\n    alpha : float, default=0.05\n        İstatistiksel anlamlılık seviyesi\n    \n    Returns:\n    --------\n    pd.DataFrame\n        Her özellik için kayma raporunu içeren DataFrame:\n        - feature_name: Özellik adı\n        - reference_mean: Referans verisinin ortalaması\n        - production_mean: Üretim verisinin ortalaması\n        - mean_diff: Ortalama farkı (üretim - referans)\n        - mean_diff_pct: Ortalama farkı yüzdesi\n        - ks_statistic: K-S test istatistiği\n        - ks_p_value: K-S test p-değeri\n        - drift_detected: Kayma tespit edildi mi (bool)\n    \n    Example:\n    --------\n    >>> report = generate_monitoring_report(train_data, production_data)\n    >>> print(report[report['drift_detected'] == True])\n    \"\"\"\n    pass  # Aşağıda tamamlanacak",
      "metadata": {},
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": "import matplotlib.pyplot as plt\nimport seaborn as sns\n\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))\n\n# Sol grafik: Kayma olmayan durum\nsns.histplot(reference_data['temperature'], ax=ax1, color='blue', \n             label='Referans', kde=True, stat='density', alpha=0.5)\nsns.histplot(production_data_ok['temperature'], ax=ax1, color='green', \n             label='Üretim (Normal)', kde=True, stat='density', alpha=0.5)\nax1.set_title('Sıcaklık Dağılımı: Kayma YOK', fontsize=14, fontweight='bold')\nax1.set_xlabel('Sıcaklık (°C)')\nax1.set_ylabel('Yoğunluk')\nax1.legend()\nax1.grid(alpha=0.3)\n\n# Sağ grafik: Kayma olan durum\nsns.histplot(reference_data['temperature'], ax=ax2, color='blue', \n             label='Referans', kde=True, stat='density', alpha=0.5)\nsns.histplot(production_data_drifted['temperature'], ax=ax2, color='red', \n             label='Üretim (KAYMA)', kde=True, stat='density', alpha=0.5)\nax2.set_title('Sıcaklık Dağılımı: CİDDİ KAYMA', fontsize=14, fontweight='bold')\nax2.set_xlabel('Sıcaklık (°C)')\nax2.set_ylabel('Yoğunluk')\nax2.legend()\nax2.grid(alpha=0.3)\n\nplt.tight_layout()\nplt.show()",
      "metadata": {},
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": "### Adım 3: Dağılımları Görselleştirme\n\nVeri kaymasını görsel olarak anlamak için histogram ve KDE (Kernel Density Estimation) grafiklerini kullanacağız.",
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "#",
        " ",
        "Ü",
        "r",
        "e",
        "t",
        "i",
        "m",
        " ",
        "V",
        "e",
        "r",
        "i",
        "s",
        "i",
        " ",
        "1",
        ":",
        " ",
        "K",
        "a",
        "y",
        "m",
        "a",
        " ",
        "Y",
        "O",
        "K",
        " ",
        "(",
        "p",
        "a",
        "r",
        "a",
        "m",
        "e",
        "t",
        "r",
        "e",
        "l",
        "e",
        "r",
        " ",
        "ç",
        "o",
        "k",
        " ",
        "b",
        "e",
        "n",
        "z",
        "e",
        "r",
        ")",
        "\n",
        "p",
        "r",
        "o",
        "d",
        "u",
        "c",
        "t",
        "i",
        "o",
        "n",
        "_",
        "d",
        "a",
        "t",
        "a",
        "_",
        "o",
        "k",
        " ",
        "=",
        " ",
        "p",
        "d",
        ".",
        "D",
        "a",
        "t",
        "a",
        "F",
        "r",
        "a",
        "m",
        "e",
        "(",
        "{",
        "\n",
        " ",
        " ",
        " ",
        " ",
        "'",
        "t",
        "e",
        "m",
        "p",
        "e",
        "r",
        "a",
        "t",
        "u",
        "r",
        "e",
        "'",
        ":",
        " ",
        "n",
        "p",
        ".",
        "r",
        "a",
        "n",
        "d",
        "o",
        "m",
        ".",
        "n",
        "o",
        "r",
        "m",
        "a",
        "l",
        "(",
        "l",
        "o",
        "c",
        "=",
        "2",
        "5",
        ".",
        "5",
        ",",
        " ",
        "s",
        "c",
        "a",
        "l",
        "e",
        "=",
        "5",
        ".",
        "2",
        ",",
        " ",
        "s",
        "i",
        "z",
        "e",
        "=",
        "5",
        "0",
        "0",
        ")",
        ",",
        "\n",
        " ",
        " ",
        " ",
        " ",
        "'",
        "p",
        "r",
        "e",
        "s",
        "s",
        "u",
        "r",
        "e",
        "'",
        ":",
        " ",
        "n",
        "p",
        ".",
        "r",
        "a",
        "n",
        "d",
        "o",
        "m",
        ".",
        "n",
        "o",
        "r",
        "m",
        "a",
        "l",
        "(",
        "l",
        "o",
        "c",
        "=",
        "1",
        "0",
        "1",
        ".",
        "2",
        ",",
        " ",
        "s",
        "c",
        "a",
        "l",
        "e",
        "=",
        "1",
        ".",
        "1",
        ",",
        " ",
        "s",
        "i",
        "z",
        "e",
        "=",
        "5",
        "0",
        "0",
        ")",
        "\n",
        "}",
        ")",
        "\n",
        "\n",
        "#",
        " ",
        "Ü",
        "r",
        "e",
        "t",
        "i",
        "m",
        " ",
        "V",
        "e",
        "r",
        "i",
        "s",
        "i",
        " ",
        "2",
        ":",
        " ",
        "C",
        "İ",
        "D",
        "D",
        "İ",
        " ",
        "K",
        "A",
        "Y",
        "M",
        "A",
        " ",
        "(",
        "s",
        "ı",
        "c",
        "a",
        "k",
        "l",
        "ı",
        "k",
        " ",
        "o",
        "r",
        "t",
        "a",
        "l",
        "a",
        "m",
        "a",
        "s",
        "ı",
        " ",
        "1",
        "0",
        " ",
        "d",
        "e",
        "r",
        "e",
        "c",
        "e",
        " ",
        "a",
        "r",
        "t",
        "t",
        "ı",
        ")",
        "\n",
        "p",
        "r",
        "o",
        "d",
        "u",
        "c",
        "t",
        "i",
        "o",
        "n",
        "_",
        "d",
        "a",
        "t",
        "a",
        "_",
        "d",
        "r",
        "i",
        "f",
        "t",
        "e",
        "d",
        " ",
        "=",
        " ",
        "p",
        "d",
        ".",
        "D",
        "a",
        "t",
        "a",
        "F",
        "r",
        "a",
        "m",
        "e",
        "(",
        "{",
        "\n",
        " ",
        " ",
        " ",
        " ",
        "'",
        "t",
        "e",
        "m",
        "p",
        "e",
        "r",
        "a",
        "t",
        "u",
        "r",
        "e",
        "'",
        ":",
        " ",
        "n",
        "p",
        ".",
        "r",
        "a",
        "n",
        "d",
        "o",
        "m",
        ".",
        "n",
        "o",
        "r",
        "m",
        "a",
        "l",
        "(",
        "l",
        "o",
        "c",
        "=",
        "3",
        "5",
        ",",
        " ",
        "s",
        "c",
        "a",
        "l",
        "e",
        "=",
        "6",
        ",",
        " ",
        "s",
        "i",
        "z",
        "e",
        "=",
        "5",
        "0",
        "0",
        ")",
        ",",
        "\n",
        " ",
        " ",
        " ",
        " ",
        "'",
        "p",
        "r",
        "e",
        "s",
        "s",
        "u",
        "r",
        "e",
        "'",
        ":",
        " ",
        "n",
        "p",
        ".",
        "r",
        "a",
        "n",
        "d",
        "o",
        "m",
        ".",
        "n",
        "o",
        "r",
        "m",
        "a",
        "l",
        "(",
        "l",
        "o",
        "c",
        "=",
        "1",
        "0",
        "1",
        ".",
        "0",
        ",",
        " ",
        "s",
        "c",
        "a",
        "l",
        "e",
        "=",
        "1",
        ".",
        "2",
        ",",
        " ",
        "s",
        "i",
        "z",
        "e",
        "=",
        "5",
        "0",
        "0",
        ")",
        "\n",
        "}",
        ")",
        "\n",
        "\n",
        "p",
        "r",
        "i",
        "n",
        "t",
        "(",
        "\"",
        "Ü",
        "r",
        "e",
        "t",
        "i",
        "m",
        " ",
        "V",
        "e",
        "r",
        "i",
        "s",
        "i",
        " ",
        "(",
        "N",
        "o",
        "r",
        "m",
        "a",
        "l",
        ")",
        " ",
        "-",
        " ",
        "İ",
        "s",
        "t",
        "a",
        "t",
        "i",
        "s",
        "t",
        "i",
        "k",
        "l",
        "e",
        "r",
        ":",
        "\"",
        ")",
        "\n",
        "p",
        "r",
        "i",
        "n",
        "t",
        "(",
        "p",
        "r",
        "o",
        "d",
        "u",
        "c",
        "t",
        "i",
        "o",
        "n",
        "_",
        "d",
        "a",
        "t",
        "a",
        "_",
        "o",
        "k",
        ".",
        "d",
        "e",
        "s",
        "c",
        "r",
        "i",
        "b",
        "e",
        "(",
        ")",
        ")",
        "\n",
        "p",
        "r",
        "i",
        "n",
        "t",
        "(",
        "\"",
        "\\",
        "n",
        "\\",
        "n",
        "Ü",
        "r",
        "e",
        "t",
        "i",
        "m",
        " ",
        "V",
        "e",
        "r",
        "i",
        "s",
        "i",
        " ",
        "(",
        "K",
        "a",
        "y",
        "m",
        "a",
        ")",
        " ",
        "-",
        " ",
        "İ",
        "s",
        "t",
        "a",
        "t",
        "i",
        "s",
        "t",
        "i",
        "k",
        "l",
        "e",
        "r",
        ":",
        "\"",
        ")",
        "\n",
        "p",
        "r",
        "i",
        "n",
        "t",
        "(",
        "p",
        "r",
        "o",
        "d",
        "u",
        "c",
        "t",
        "i",
        "o",
        "n",
        "_",
        "d",
        "a",
        "t",
        "a",
        "_",
        "d",
        "r",
        "i",
        "f",
        "t",
        "e",
        "d",
        ".",
        "d",
        "e",
        "s",
        "c",
        "r",
        "i",
        "b",
        "e",
        "(",
        ")",
        ")"
      ],
      "metadata": {},
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": "### Adım 2: Üretim Verileri Oluşturma",
      "metadata": {}
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom scipy.stats import ks_2samp\n\n# --- 1. Sentetik Veri Üretimi ---\n# a) Referans Veri (Modelin eğitildiği veri)\nnp.random.seed(42)\nreference_data = pd.DataFrame({\n    'temperature': np.random.normal(loc=25, scale=5, size=1000),\n    'pressure': np.random.normal(loc=101.3, scale=1, size=1000)\n})\n\n# b) Üretim Verisi 1 (Kayma Yok)\nproduction_data_ok = pd.DataFrame({\n    'temperature': np.random.normal(loc=25.5, scale=5.2, size=500), # Hafif, önemsiz değişiklik\n    'pressure': np.random.normal(loc=101.2, scale=1.1, size=500)\n})\n\n# c) Üretim Verisi 2 (Ciddi Kayma Var)\n# Sıcaklıkların ortalaması yaz mevsimi nedeniyle belirgin şekilde artmış olsun.\nproduction_data_drifted = pd.DataFrame({\n    'temperature': np.random.normal(loc=35, scale=6, size=500), # Ortalamada ciddi kayma\n    'pressure': np.random.normal(loc=101.0, scale=1.2, size=500)\n})\n\n# --- 2. Veri Dağılımlarını Görselleştirme ---\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6), sharey=True)\n\n# Grafik 1: Kayma Olmayan Durum\nsns.histplot(reference_data['temperature'], ax=ax1, color='blue', label='Referans', kde=True, stat='density')\nsns.histplot(production_data_ok['temperature'], ax=ax1, color='green', label='Üretim (OK)', kde=True, stat='density')\nax1.set_title('Sıcaklık Dağılımı (Kayma Yok)')\nax1.legend()\n\n# Grafik 2: Kayma Olan Durum\nsns.histplot(reference_data['temperature'], ax=ax2, color='blue', label='Referans', kde=True, stat='density')\nsns.histplot(production_data_drifted['temperature'], ax=ax2, color='red', label='Üretim (Kayma Var)', kde=True, stat='density')\nax2.set_title('Sıcaklık Dağılımı (CİDDİ KAYMA)')\nax2.legend()\n\nplt.show()\n\n# --- 3. İstatistiksel Test ile Kaymayı Tespit Etme ---\ndef check_drift(reference_series, production_series, feature_name, alpha=0.05):\n    \"\"\"\n    Performs the K-S test to check for data drift between two series.\n    \"\"\"\n    ks_statistic, p_value = ks_2samp(reference_series, production_series)\n    \n    print(f\"\\n--- {feature_name} için Kayma Testi ---\")\n    print(f\"K-S İstatistiği: {ks_statistic:.4f}\")\n    print(f\"P-Değeri: {p_value:.4f}\")\n    \n    if p_value < alpha:\n        print(f\"Sonuç: Hipotez reddedildi. Veri kayması TESPİT EDİLDİ (p < {alpha}).\")\n        return True\n    else:\n        print(f\"Sonuç: Hipotez reddedilemedi. Anlamlı bir veri kayması YOK (p >= {alpha}).\")\n        return False\n\n# Testleri çalıştır\ncheck_drift(reference_data['temperature'], production_data_ok['temperature'], 'Sıcaklık (Durum OK)')\ncheck_drift(reference_data['temperature'], production_data_drifted['temperature'], 'Sıcaklık (Durum KAYMA)')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 4. Sürekli Teslimat/Dağıtım (CI/CD)\n\nCI (Sürekli Entegrasyon) kodun kalitesini kontrol eder. CD ise bu kaliteli kodun (veya modelin) üretim ortamına otomatik olarak dağıtılmasını sağlar.\n\n**Basitleştirilmiş bir MLOps CD Pipeline'ı:**\n\n1.  Bir veri bilimci, yeni verilerle veya daha iyi bir teknikle eğittiği yeni bir modeli `MLflow`'a kaydeder.\n2.  Bu yeni model, bir \"hazırlık\" (staging) ortamında bir dizi otomatik teste tabi tutulur:\n    *   Modelin performansı, mevcut üretimdeki modelden daha mı iyi?\n    *   Modelin tahmin gecikmesi kabul edilebilir sınırlar içinde mi?\n    *   Model, bilinen kritik veri örnekleri (edge cases) için mantıklı tahminler üretiyor mu?\n3.  Tüm testler başarılı olursa, bir yetkilinin onayıyla (Sürekli Teslimat) veya tamamen otomatik olarak (Sürekli Dağıtım), yeni model, üretimdeki eski modelin yerini alır.\n\nBu döngü, MLOps'un son halkasıdır ve ML sistemlerinin sürekli olarak öğrenmesini ve iyileşmesini sağlar.\n\n### Alıştırma: Bir İzleme Raporu Oluşturun\n\n1.  Yukarıdaki `reference_data` ve `production_data_drifted` DataFrame'lerini kullanarak bir fonksiyon yazın.\n2.  Bu fonksiyon, iki DataFrame'i almalı ve her bir sayısal sütun için (`temperature`, `pressure`) aşağıdaki bilgileri içeren bir özet `pandas.DataFrame` döndürmelidir:\n    *   Sütun Adı\n    *   Referans Ortalaması\n    *   Üretim Ortalaması\n    *   K-S Testi p-değeri\n    *   `drift_detected` (True/False) adında bir sütun.\n3.  Bu fonksiyonun çıktısı, bir veri bilimcinin veya operasyon ekibinin modelin sağlığını hızla değerlendirebileceği basit bir izleme raporu olacaktır."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Alıştırma için çözüm alanı\ndef generate_monitoring_report(ref_df, prod_df, alpha=0.05):\n    report_data = []\n    numeric_cols = ref_df.select_dtypes(include=np.number).columns\n    \n    for col in numeric_cols:\n        if col in prod_df.columns:\n            ks_stat, p_value = ks_2samp(ref_df[col], prod_df[col])\n            drift_detected = p_value < alpha\n            \n            report_data.append({\n                \"feature_name\": col,\n                \"reference_mean\": ref_df[col].mean(),\n                \"production_mean\": prod_df[col].mean(),\n                \"ks_p_value\": p_value,\n                \"drift_detected\": drift_detected\n            })\n            \n    return pd.DataFrame(report_data)\n\nmonitoring_report = generate_monitoring_report(reference_data, production_data_drifted)\nprint(\"--- Veri Sağlığı İzleme Raporu ---\")\ndisplay(monitoring_report)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Haftanın Özeti\n\nBu hafta, MLOps yaşam döngüsünün son ve en kritik halkalarını tamamladık.\n- Modeller statik değildir; dünya değiştikçe performansları düşer. **Veri Kayması** bu düşüşün en yaygın nedenidir.\n- Üretimdeki bir modeli, hem sistem sağlığı (operasyonel metrikler) hem de veri ve tahmin kalitesi (performans ve kayma metrikleri) açısından sürekli **izlemeliyiz**.\n- **İstatistiksel testler** (K-S testi gibi), veri kaymasını objektif olarak tespit etmek için güçlü araçlardır.\n- **Sürekli Teslimat (CD)**, test edilmiş ve onaylanmış yeni modellerin üretim ortamına güvenli ve otomatik bir şekilde dağıtılmasını sağlayarak MLOps döngüsünü tamamlar.\n\n### Sonraki Adımlar\n\nGeleneksel ML sistemlerini baştan sona (versiyon kontrolünden izlemeye kadar) nasıl inşa edeceğimizi öğrendik. Artık, yapay zekanın en heyecan verici ve en güncel alanına girmeye hazırız. Bir sonraki hafta, **Hafta 8: Büyük Dil Modelleri (LLM) Temelleri ve Prompt Mühendisliği**'nde, metin anlayan, üreten ve bizimle diyalog kurabilen devasa modellerin dünyasına ilk adımımızı atacağız.\n\n---\n\n## **Hafta 8: Büyük Dil Modelleri (LLM) Temelleri ve Prompt Mühendisliği**\n```python"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.8.0"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}