{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "22c1c705",
   "metadata": {},
   "source": [
    "# Moduł 7: Jakość targetu i etykiet\n",
    "\n",
    "**Wersja:** uczestnika  \n",
    "**Cel:** zmierzyć wpływ kontrolowanego losowego szumu etykiet na model i oddzielić jakość targetu od jakości modelu oraz progu decyzyjnego  \n",
    "**Czas orientacyjny:** 45–55 min  \n",
    "**Dane:** customer360_target_clean.csv  \n",
    "**Artefakt końcowy:** wykres F1/ROC-AUC vs label noise + rekomendacja governance\n",
    "\n",
    "Notebook jest częścią wspólnego case'u **Customer 360**. Dane są syntetyczne i służą wyłącznie ćwiczeniu."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "691d01f2",
   "metadata": {},
   "source": [
    "## Jak pracować\n",
    "\n",
    "1. Uruchamiaj komórki od góry do dołu.\n",
    "2. Najpierw zapisz obserwację z danych. Dopiero później formułuj hipotezę o przyczynie.\n",
    "3. W rekomendacji wskaż dowód, właściciela działania i warunek ponownej oceny.\n",
    "4. Wynik statystyczny jest sygnałem diagnostycznym. Sam nie przesądza o zatrzymaniu modelu, zmianie progu ani retrainingu."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "236e683e",
   "metadata": {},
   "source": [
    "## Granice interpretacji\n",
    "\n",
    "- Flip labels w tym notebooku symuluje głównie losowy szum. Nie odwzorowuje wszystkich mechanizmów błędnej etykiety.\n",
    "- Nie ma uniwersalnego progu bezpiecznego szumu. Ewentualny próg działania musi wynikać z kryterium danego zastosowania.\n",
    "- Metryki odnoszą się do wersji targetu użytej jako referencja. Zaszumiony test może zniekształcić ocenę modelu.\n",
    "- Zmiana progu decyzyjnego nie naprawia błędnej definicji targetu."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "985853e7",
   "metadata": {},
   "source": [
    "## Reguła operacyjna laboratorium\n",
    "Eksperyment z flip labels pokazuje wpływ losowego szumu treningowego. Nie uogólniaj go na każdy błąd targetu i nie wyznaczaj uniwersalnego „krytycznego poziomu” szumu. W praktyce tolerancja zależy od definicji targetu, procesu etykietowania i skutku biznesowego."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bdf89d0f",
   "metadata": {},
   "source": [
    "## Dane wejściowe i manifest\n",
    "Dane: `customer360_target_clean.csv`.  \n",
    "Opis kolumn i reguł laboratoryjnych: `manifests/M07_data_manifest.csv` w paczce zbiorczej albo `data_manifest.csv` w paczce modułowej."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "818d8bce",
   "metadata": {
    "tags": [
     "setup"
    ]
   },
   "outputs": [],
   "source": [
    "from pathlib import Path\n",
    "import sys\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "DATA_DIR = Path('data')\n",
    "if not DATA_DIR.exists():\n",
    "    DATA_DIR = Path('..') / 'data'\n",
    "assert DATA_DIR.exists(), 'Nie znaleziono katalogu data. Uruchom notebook z katalogu paczki lub zachowaj strukturę ZIP.'\n",
    "print('Python:', sys.version.split()[0])\n",
    "print('pandas:', pd.__version__)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "01949e7b",
   "metadata": {},
   "source": [
    "## 1. Przygotowanie czystej referencji\n",
    "\n",
    "Podziel dane na train/test. Test pozostaw z czystym targetem, aby w ćwiczeniu izolować wpływ szumu treningowego."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "017fca7d",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.pipeline import make_pipeline\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.metrics import f1_score, roc_auc_score\n",
    "df=pd.read_csv(DATA_DIR/'customer360_target_clean.csv')\n",
    "# TODO: X, y, split"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48771d0c",
   "metadata": {},
   "source": [
    "## 2. Kontrolowany label noise 0–30% z powtórzeniami\n",
    "\n",
    "Dla każdego poziomu szumu odwróć losowo wskazany odsetek etykiet **tylko w train**. Powtórz eksperyment 30 razy z różnymi ziarnami losowymi. Test pozostaje z czystym targetem.\n",
    "\n",
    "Raportuj średnią i odchylenie standardowe F1 oraz ROC-AUC. Wielokrotne losowania ograniczają ryzyko, że pojedynczy przypadkowy flip da mylący wykres."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "da0a26a9",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "levels=[0,.05,.10,.20,.30]\n",
    "n_repeats=30\n",
    "raw_results=pd.DataFrame(columns=['noise','rep','F1','ROC_AUC'])\n",
    "results=pd.DataFrame(columns=['noise','F1_mean','F1_sd','ROC_AUC_mean','ROC_AUC_sd'])\n",
    "# TODO: wykonaj n_repeats symulacji dla każdego poziomu noise.\n",
    "display(results)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c092cf89",
   "metadata": {},
   "source": [
    "## 3. Wykres wpływu i niepewność\n",
    "\n",
    "Narysuj średnią F1 i ROC-AUC dla kolejnych poziomów szumu oraz pokaż zmienność między powtórzeniami. Nie wyznaczaj „krytycznego poziomu” label noise. Zamiast tego opisz kierunek, skalę i zmienność efektu oraz ograniczenie eksperymentu."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a5383a96",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "if len(results):\n",
    "    # TODO: narysuj mean ± sd dla F1 i ROC_AUC.\n",
    "    pass\n",
    "else:\n",
    "    print('Uzupełnij krok 2, aby narysować wykres.')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e33bb27",
   "metadata": {},
   "source": [
    "## 4. Rekomendacja Data Governance\n",
    "\n",
    "Wniosek ma dotyczyć procesu etykietowania: definicji, wersji, okna obserwacji, właściciela i kontroli próby."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1ff8b38e",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "recommendation={'observation':'','limitation':'','governance':'','decision_rule':''}\n",
    "# TODO: uzupełnij wniosek bez wyznaczania uniwersalnego progu label noise.\n",
    "recommendation"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2e5c379",
   "metadata": {},
   "source": [
    "## Zadanie rozszerzające\n",
    "\n",
    "Powtórz eksperyment z szumem skoncentrowanym w jednym segmencie i porównaj z losowym flipem."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "200bcbdf",
   "metadata": {},
   "source": [
    "## Kryteria akceptacji ćwiczenia\n",
    "- szum dodajesz tylko do y_train, a y_test pozostaje czystą referencją\n",
    "- dla każdego poziomu 0–30% wykonujesz wielokrotne losowania i raportujesz średnią oraz zmienność\n",
    "- nie wyznaczasz uniwersalnego krytycznego poziomu label noise\n",
    "\n",
    "Przed oddaniem wykonaj **Restart Kernel and Run All**. Notebook nie powinien zależeć od ręcznie ustawionego stanu poprzednich komórek."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d125cfdc",
   "metadata": {},
   "source": [
    "## Co oddajesz\n",
    "\n",
    "Zachowaj tabelę lub wykres będący wynikiem ćwiczenia oraz krótki komentarz: **obserwacja → hipoteza → potrzebny dowód → rekomendacja / dalszy krok**. Jeżeli nie da się rozstrzygnąć przyczyny na podstawie danych z notebooka, oznacz ją jako hipotezę i wskaż brakujący artefakt."
   ]
  }
 ],
 "metadata": {
  "course": {
   "generated": "2026-08-28",
   "module": 7,
   "variant": "participant"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.x"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
