{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":29653,"databundleVersionId":2420395,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# ============================================================\n# PART 1\n# Import Libraries\n# ============================================================\n\nimport os\nimport random\nimport warnings\n\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport pydicom\nimport matplotlib.pyplot as plt\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.utils.class_weight import compute_class_weight\nfrom sklearn.metrics import (\n    classification_report,\n    confusion_matrix,\n    roc_curve,\n    auc,\n    accuracy_score,\n    precision_score,\n    recall_score,\n    f1_score\n)\n\nimport tensorflow as tf\nfrom tensorflow.keras import layers\nfrom tensorflow.keras import Model\nfrom tensorflow.keras import regularizers\n\nwarnings.filterwarnings(\"ignore\")\n\nprint(\"TensorFlow Version :\", tf.__version__)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:41:14.568238Z","iopub.execute_input":"2026-07-11T02:41:14.568932Z","iopub.status.idle":"2026-07-11T02:41:14.574820Z","shell.execute_reply.started":"2026-07-11T02:41:14.568905Z","shell.execute_reply":"2026-07-11T02:41:14.573856Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Configuration\n# ============================================================\n\nPATH = \"/kaggle/input/rsna-miccai-brain-tumor-radiogenomic-classification/\"\n\nIMG_SIZE = 96\n\nNUM_SLICES = 16\n\nBATCH_SIZE = 2\n\nEPOCHS = 60\n\nSEED = 42\n\nMODALITIES = [\n    \"FLAIR\",\n    \"T1w\",\n    \"T1wCE\",\n    \"T2w\"\n]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:41:14.597165Z","iopub.execute_input":"2026-07-11T02:41:14.597809Z","iopub.status.idle":"2026-07-11T02:41:14.601604Z","shell.execute_reply.started":"2026-07-11T02:41:14.597793Z","shell.execute_reply":"2026-07-11T02:41:14.600791Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Fix Random Seed\n# ============================================================\n\nrandom.seed(SEED)\n\nnp.random.seed(SEED)\n\ntf.random.set_seed(SEED)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:41:14.635786Z","iopub.execute_input":"2026-07-11T02:41:14.636458Z","iopub.status.idle":"2026-07-11T02:41:14.655162Z","shell.execute_reply.started":"2026-07-11T02:41:14.636440Z","shell.execute_reply":"2026-07-11T02:41:14.654319Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Load Labels\n# ============================================================\n\ntrain_df = pd.read_csv(\n    PATH + \"train_labels.csv\"\n)\n\nprint(train_df.head())\n\nprint()\n\nprint(train_df.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:41:14.691703Z","iopub.execute_input":"2026-07-11T02:41:14.691919Z","iopub.status.idle":"2026-07-11T02:41:14.700311Z","shell.execute_reply.started":"2026-07-11T02:41:14.691894Z","shell.execute_reply":"2026-07-11T02:41:14.699290Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# MRI Preprocessing\n# ============================================================\n\ndef load_dicom_image(filepath):\n\n    dcm = pydicom.dcmread(filepath)\n\n    img = dcm.pixel_array.astype(np.float32)\n\n    # Z-score Normalization\n              # Z-score\n    img = (img - np.mean(img)) / (np.std(img) + 1e-8)\n\n# Percentile normalization\n    p1 = np.percentile(img, 1)\n    p99 = np.percentile(img, 99)\n\n    img = np.clip(img, p1, p99)\n\n    img = (img - p1) / (p99 - p1 + 1e-8)\n\n    img = np.clip(img, 0, 1)\n\n    # Resize\n    img = cv2.resize(\n        img,\n        (IMG_SIZE, IMG_SIZE)\n    )\n\n    img = np.expand_dims(\n        img,\n        axis=-1\n    )\n\n    return img","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:41:14.713848Z","iopub.execute_input":"2026-07-11T02:41:14.714468Z","iopub.status.idle":"2026-07-11T02:41:14.719225Z","shell.execute_reply.started":"2026-07-11T02:41:14.714448Z","shell.execute_reply":"2026-07-11T02:41:14.718621Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# PARTIE 2\n# Chargement d'un patient\n# ============================================================\n\ndef load_patient_data(patient_id):\n\n    patient_folder = os.path.join(\n        PATH,\n        \"train\",\n        str(patient_id).zfill(5)\n    )\n\n    if not os.path.exists(patient_folder):\n        return None\n\n    flair_folder = os.path.join(\n        patient_folder,\n        \"FLAIR\"\n    )\n\n    if not os.path.exists(flair_folder):\n        return None\n\n    flair_files = sorted([\n        f for f in os.listdir(flair_folder)\n        if f.endswith(\".dcm\")\n    ])\n\n    if len(flair_files) == 0:\n        return None\n\n    total_slices = len(flair_files)\n\n    # Sélection des coupes centrales\n    if total_slices <= NUM_SLICES:\n\n        indices = np.arange(total_slices)\n\n    else:\n\n        center = total_slices // 2\n\n        start = center - NUM_SLICES // 2\n\n        end = center + NUM_SLICES // 2\n\n        indices = np.arange(start, end)\n\n    volume = []\n\n    for idx in indices:\n\n        channels = []\n\n        for modality in MODALITIES:\n\n            modality_folder = os.path.join(\n                patient_folder,\n                modality\n            )\n\n            modality_files = sorted([\n                f for f in os.listdir(modality_folder)\n                if f.endswith(\".dcm\")\n            ])\n\n            if len(modality_files) == 0:\n\n                img = np.zeros(\n                    (IMG_SIZE, IMG_SIZE, 1),\n                    dtype=np.float32\n                )\n\n            else:\n\n                idx_real = min(\n                    idx,\n                    len(modality_files)-1\n                )\n\n                img_path = os.path.join(\n                    modality_folder,\n                    modality_files[idx_real]\n                )\n\n                img = load_dicom_image(img_path)\n\n            channels.append(img)\n\n        img = np.concatenate(\n            channels,\n            axis=-1\n        )\n\n        volume.append(img)\n\n    volume = np.array(\n        volume,\n        dtype=np.float32\n    )\n\n    while volume.shape[0] < NUM_SLICES:\n\n        volume = np.concatenate(\n            [volume, volume[-1:]],\n            axis=0\n        )\n\n    return volume","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:41:14.732685Z","iopub.execute_input":"2026-07-11T02:41:14.732843Z","iopub.status.idle":"2026-07-11T02:41:14.741194Z","shell.execute_reply.started":"2026-07-11T02:41:14.732831Z","shell.execute_reply":"2026-07-11T02:41:14.740376Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"patient = load_patient_data(0)\n\nprint(patient.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:41:14.751693Z","iopub.execute_input":"2026-07-11T02:41:14.752290Z","iopub.status.idle":"2026-07-11T02:41:15.303530Z","shell.execute_reply.started":"2026-07-11T02:41:14.752274Z","shell.execute_reply":"2026-07-11T02:41:15.302731Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Construction du Dataset\n# ============================================================\n\nX = []\n\ny = []\n\nprint(\"Loading dataset ...\")\n\nfor _, row in train_df.iterrows():\n\n    patient = load_patient_data(\n        row[\"BraTS21ID\"]\n    )\n\n    if patient is not None:\n\n        X.append(patient)\n\n        y.append(row[\"MGMT_value\"])\n\nX = np.array(\n    X,\n    dtype=np.float32\n)\n\ny = np.array(\n    y,\n    dtype=np.float32\n)\n\nprint()\n\nprint(\"Dataset loaded.\")\n\nprint(\"X shape :\", X.shape)\n\nprint(\"y shape :\", y.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:41:15.305064Z","iopub.execute_input":"2026-07-11T02:41:15.305335Z","iopub.status.idle":"2026-07-11T02:45:13.257607Z","shell.execute_reply.started":"2026-07-11T02:41:15.305317Z","shell.execute_reply":"2026-07-11T02:45:13.256614Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(np.unique(y, return_counts=True))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:45:13.258624Z","iopub.execute_input":"2026-07-11T02:45:13.259034Z","iopub.status.idle":"2026-07-11T02:45:13.265838Z","shell.execute_reply.started":"2026-07-11T02:45:13.259009Z","shell.execute_reply":"2026-07-11T02:45:13.265139Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Train / Validation / Test\n# ============================================================\n\nX_train, X_temp, y_train, y_temp = train_test_split(\n\n    X,\n\n    y,\n\n    test_size=0.30,\n\n    stratify=y,\n\n    random_state=SEED\n\n)\n\nX_val, X_test, y_val, y_test = train_test_split(\n\n    X_temp,\n\n    y_temp,\n\n    test_size=0.50,\n\n    stratify=y_temp,\n\n    random_state=SEED\n\n)\n\nprint()\n\nprint(\"Train :\", X_train.shape)\n\nprint(\"Validation :\", X_val.shape)\n\nprint(\"Test :\", X_test.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:45:13.268132Z","iopub.execute_input":"2026-07-11T02:45:13.268760Z","iopub.status.idle":"2026-07-11T02:45:13.738913Z","shell.execute_reply.started":"2026-07-11T02:45:13.268738Z","shell.execute_reply":"2026-07-11T02:45:13.738023Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Class Weights\n# ============================================================\n\nweights = compute_class_weight(\n\n    class_weight=\"balanced\",\n\n    classes=np.unique(y_train),\n\n    y=y_train\n\n)\n\nclass_weights = {\n\n    0: weights[0],\n\n    1: weights[1]\n\n}\n\nprint(class_weights)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:45:13.739807Z","iopub.execute_input":"2026-07-11T02:45:13.740235Z","iopub.status.idle":"2026-07-11T02:45:13.746370Z","shell.execute_reply.started":"2026-07-11T02:45:13.740209Z","shell.execute_reply":"2026-07-11T02:45:13.745554Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Residual Block 3D\n# ============================================================\n\nfrom tensorflow.keras import regularizers\n\ndef residual_block(x, filters, stride=1):\n\n    shortcut = x\n\n    # Première convolution\n    x = layers.Conv3D(\n        filters,\n        kernel_size=3,\n        strides=stride,\n        padding=\"same\",\n        use_bias=False,\n        kernel_regularizer=regularizers.l2(1e-4)\n    )(x)\n\n    x = layers.BatchNormalization()(x)\n    x = layers.Activation(\"relu\")(x)\n\n    # Deuxième convolution\n    x = layers.Conv3D(\n        filters,\n        kernel_size=3,\n        padding=\"same\",\n        use_bias=False,\n        kernel_regularizer=regularizers.l2(1e-4)\n    )(x)\n\n    x = layers.BatchNormalization()(x)\n\n    # Adapter le shortcut si nécessaire\n    if stride != 1 or shortcut.shape[-1] != filters:\n\n        shortcut = layers.Conv3D(\n            filters,\n            kernel_size=1,\n            strides=stride,\n            padding=\"same\",\n            use_bias=False\n        )(shortcut)\n\n        shortcut = layers.BatchNormalization()(shortcut)\n\n    x = layers.Add()([x, shortcut])\n\n    x = layers.Activation(\"relu\")(x)\n\n    return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:45:13.747138Z","iopub.execute_input":"2026-07-11T02:45:13.747333Z","iopub.status.idle":"2026-07-11T02:45:13.759634Z","shell.execute_reply.started":"2026-07-11T02:45:13.747319Z","shell.execute_reply":"2026-07-11T02:45:13.759025Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Squeeze-and-Excitation Block\n# ============================================================\n\ndef se_block(x, ratio=8):\n\n    channels = int(x.shape[-1])\n\n    se = layers.GlobalAveragePooling3D()(x)\n\n    se = layers.Dense(\n        channels // ratio,\n        activation=\"relu\"\n    )(se)\n\n    se = layers.Dense(\n        channels,\n        activation=\"sigmoid\"\n    )(se)\n\n    se = layers.Reshape((1, 1, 1, channels))(se)\n\n    return layers.Multiply()([x, se])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:45:13.760530Z","iopub.execute_input":"2026-07-11T02:45:13.760820Z","iopub.status.idle":"2026-07-11T02:45:13.775951Z","shell.execute_reply.started":"2026-07-11T02:45:13.760806Z","shell.execute_reply":"2026-07-11T02:45:13.775121Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# 3D ResNet\n# ============================================================\n\ndef build_3d_resnet(input_shape):\n\n    inputs = layers.Input(shape=input_shape)\n\n    # Bloc initial\n    x = layers.Conv3D(\n        16,\n        kernel_size=3,\n        padding=\"same\",\n        use_bias=False\n    )(inputs)\n\n    x = layers.BatchNormalization()(x)\n\n    x = layers.Activation(\"relu\")(x)\n\n    # Bloc 1\n    x = residual_block(x, 16)\n    x = se_block(x)\n\n    x = layers.MaxPooling3D(pool_size=2)(x)\n\n    # Bloc 2\n    x = residual_block(x, 32, stride=2)\n    x = se_block(x)\n\n    # Bloc 3\n    x = residual_block(x, 64, stride=2)\n    x = se_block(x)\n\n    # Classification\n    x = layers.GlobalAveragePooling3D()(x)\n\n    x = layers.Dropout(0.40)(x)\n\n    x = layers.Dense(\n        128,\n        activation=\"relu\",\n        kernel_regularizer=regularizers.l2(1e-4)\n    )(x)\n\n    x = layers.Dropout(0.50)(x)\n\n    outputs = layers.Dense(\n        1,\n        activation=\"sigmoid\"\n    )(x)\n\n    model = Model(inputs, outputs)\n\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:45:13.776763Z","iopub.execute_input":"2026-07-11T02:45:13.777113Z","iopub.status.idle":"2026-07-11T02:45:13.790108Z","shell.execute_reply.started":"2026-07-11T02:45:13.777088Z","shell.execute_reply":"2026-07-11T02:45:13.789442Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"input_shape = X_train.shape[1:]\n\nprint(\"Input Shape :\", input_shape)\n\nmodel = build_3d_resnet(input_shape)\n\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:45:13.790996Z","iopub.execute_input":"2026-07-11T02:45:13.791356Z","iopub.status.idle":"2026-07-11T02:45:14.057533Z","shell.execute_reply.started":"2026-07-11T02:45:13.791330Z","shell.execute_reply":"2026-07-11T02:45:14.056912Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"optimizer = tf.keras.optimizers.AdamW(\n    learning_rate=1e-4,\n    weight_decay=1e-5\n)\n\nmodel.compile(\n\n    optimizer=optimizer,\n\n    loss=tf.keras.losses.BinaryFocalCrossentropy(\n        gamma=2.0\n    ),\n\n    metrics=[\n        \"accuracy\",\n        tf.keras.metrics.AUC(name=\"auc\"),\n        tf.keras.metrics.Precision(name=\"precision\"),\n        tf.keras.metrics.Recall(name=\"recall\")\n    ]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:45:14.059819Z","iopub.execute_input":"2026-07-11T02:45:14.060498Z","iopub.status.idle":"2026-07-11T02:45:14.087168Z","shell.execute_reply.started":"2026-07-11T02:45:14.060478Z","shell.execute_reply":"2026-07-11T02:45:14.086651Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Callbacks\n# ============================================================\n\ncallbacks = [\n\n    tf.keras.callbacks.ModelCheckpoint(\n\n        \"best_resnet3d.keras\",\n\n        monitor=\"val_auc\",\n\n        mode=\"max\",\n\n        save_best_only=True,\n\n        verbose=1\n\n    ),\n\n    tf.keras.callbacks.EarlyStopping(\n\n        monitor=\"val_auc\",\n\n        mode=\"max\",\n\n        patience=8,\n\n        restore_best_weights=True,\n\n        verbose=1\n\n    ),\n\n    tf.keras.callbacks.ReduceLROnPlateau(\n\n        monitor=\"val_loss\",\n\n        factor=0.5,\n\n        patience=3,\n\n        min_lr=1e-6,\n\n        verbose=1\n\n    )\n\n]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:45:14.087766Z","iopub.execute_input":"2026-07-11T02:45:14.088055Z","iopub.status.idle":"2026-07-11T02:45:14.092929Z","shell.execute_reply.started":"2026-07-11T02:45:14.088038Z","shell.execute_reply":"2026-07-11T02:45:14.092167Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Training\n# ============================================================\n\nhistory = model.fit(\n\n    X_train,\n    y_train,\n\n    validation_data=(X_val,y_val),\n\n    epochs=EPOCHS,\n\n    batch_size=BATCH_SIZE,\n\n    shuffle=True,\n\n    callbacks=callbacks,\n\n    verbose=1\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:45:14.093841Z","iopub.execute_input":"2026-07-11T02:45:14.094140Z","iopub.status.idle":"2026-07-11T02:47:48.932847Z","shell.execute_reply.started":"2026-07-11T02:45:14.094124Z","shell.execute_reply":"2026-07-11T02:47:48.932265Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.save(\"Final_ResNet3D.keras\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:48.933897Z","iopub.execute_input":"2026-07-11T02:47:48.934189Z","iopub.status.idle":"2026-07-11T02:47:49.094704Z","shell.execute_reply.started":"2026-07-11T02:47:48.934159Z","shell.execute_reply":"2026-07-11T02:47:49.093833Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Training Curves\n# ============================================================\n\nplt.figure(figsize=(15,5))\n\n# Accuracy\nplt.subplot(1,3,1)\n\nplt.plot(history.history[\"accuracy\"],label=\"Train\")\n\nplt.plot(history.history[\"val_accuracy\"],label=\"Validation\")\n\nplt.title(\"Accuracy\")\n\nplt.legend()\n\n# Loss\nplt.subplot(1,3,2)\n\nplt.plot(history.history[\"loss\"],label=\"Train\")\n\nplt.plot(history.history[\"val_loss\"],label=\"Validation\")\n\nplt.title(\"Loss\")\n\nplt.legend()\n\n# AUC\nplt.subplot(1,3,3)\n\nplt.plot(history.history[\"auc\"],label=\"Train\")\n\nplt.plot(history.history[\"val_auc\"],label=\"Validation\")\n\nplt.title(\"AUC\")\n\nplt.legend()\n\nplt.tight_layout()\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:49.095525Z","iopub.execute_input":"2026-07-11T02:47:49.096279Z","iopub.status.idle":"2026-07-11T02:47:50.299475Z","shell.execute_reply.started":"2026-07-11T02:47:49.096259Z","shell.execute_reply":"2026-07-11T02:47:50.298555Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"best_epoch = np.argmax(history.history[\"val_auc\"]) + 1\n\nbest_auc = np.max(history.history[\"val_auc\"])\n\nprint(\"Best Epoch :\", best_epoch)\n\nprint(\"Best Validation AUC :\", best_auc)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:50.300304Z","iopub.execute_input":"2026-07-11T02:47:50.301099Z","iopub.status.idle":"2026-07-11T02:47:50.306155Z","shell.execute_reply.started":"2026-07-11T02:47:50.301079Z","shell.execute_reply":"2026-07-11T02:47:50.305321Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(X.dtype)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:50.307131Z","iopub.execute_input":"2026-07-11T02:47:50.307381Z","iopub.status.idle":"2026-07-11T02:47:50.319434Z","shell.execute_reply.started":"2026-07-11T02:47:50.307359Z","shell.execute_reply":"2026-07-11T02:47:50.318815Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Evaluation\n# ============================================================\n\nresults = model.evaluate(\n    X_test,\n    y_test,\n    verbose=1\n)\n\nprint(\"\\n========== Test Results ==========\")\n\nfor name, value in zip(model.metrics_names, results):\n    print(f\"{name} : {value:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:50.320278Z","iopub.execute_input":"2026-07-11T02:47:50.320573Z","iopub.status.idle":"2026-07-11T02:47:54.203326Z","shell.execute_reply.started":"2026-07-11T02:47:50.320552Z","shell.execute_reply":"2026-07-11T02:47:54.202708Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Predictions\n# ============================================================\n\ny_prob = model.predict(\n    X_test,\n    verbose=1\n)\n\ny_prob = y_prob.flatten()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:54.204173Z","iopub.execute_input":"2026-07-11T02:47:54.204508Z","iopub.status.idle":"2026-07-11T02:47:56.946376Z","shell.execute_reply.started":"2026-07-11T02:47:54.204489Z","shell.execute_reply":"2026-07-11T02:47:56.945496Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Predictions sur Validation\n\nval_prob = model.predict(X_val).flatten()\n\nbest_threshold = 0.5\n\nbest_f1 = 0\n\nfor th in np.arange(0.30, 0.71, 0.01):\n\n    pred = (val_prob >= th).astype(int)\n\n    score = f1_score(y_val, pred)\n\n    if score > best_f1:\n\n        best_f1 = score\n\n        best_threshold = th\n\nprint(\"Best Threshold :\", best_threshold)\nprint(\"Best F1 :\", best_f1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:56.947251Z","iopub.execute_input":"2026-07-11T02:47:56.947515Z","iopub.status.idle":"2026-07-11T02:47:57.712592Z","shell.execute_reply.started":"2026-07-11T02:47:56.947497Z","shell.execute_reply":"2026-07-11T02:47:57.711728Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Best Threshold :\", best_threshold)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:57.713347Z","iopub.execute_input":"2026-07-11T02:47:57.713569Z","iopub.status.idle":"2026-07-11T02:47:57.717879Z","shell.execute_reply.started":"2026-07-11T02:47:57.713553Z","shell.execute_reply":"2026-07-11T02:47:57.717201Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Prediction sur Test\n\ny_prob = model.predict(X_test).flatten()\n\ny_pred = (y_prob >= best_threshold).astype(int)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:57.718796Z","iopub.execute_input":"2026-07-11T02:47:57.719053Z","iopub.status.idle":"2026-07-11T02:47:58.446525Z","shell.execute_reply.started":"2026-07-11T02:47:57.719032Z","shell.execute_reply":"2026-07-11T02:47:58.445674Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Metrics\n# ============================================================\n\nacc = accuracy_score(y_test, y_pred)\n\nprec = precision_score(y_test, y_pred)\n\nrec = recall_score(y_test, y_pred)\n\nf1 = f1_score(y_test, y_pred)\n\nprint()\n\nprint(\"Accuracy :\", acc)\n\nprint(\"Precision :\", prec)\n\nprint(\"Recall :\", rec)\n\nprint(\"F1 Score :\", f1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:58.447462Z","iopub.execute_input":"2026-07-11T02:47:58.447943Z","iopub.status.idle":"2026-07-11T02:47:58.459282Z","shell.execute_reply.started":"2026-07-11T02:47:58.447924Z","shell.execute_reply":"2026-07-11T02:47:58.458744Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Classification Report\n# ============================================================\n\nprint()\n\nprint(classification_report(\n    y_test,\n    y_pred,\n    digits=4\n))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:58.460282Z","iopub.execute_input":"2026-07-11T02:47:58.461199Z","iopub.status.idle":"2026-07-11T02:47:58.477464Z","shell.execute_reply.started":"2026-07-11T02:47:58.461170Z","shell.execute_reply":"2026-07-11T02:47:58.476868Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Confusion Matrix\n# ============================================================\n\ncm = confusion_matrix(\n    y_test,\n    y_pred\n)\n\nprint(cm)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:58.478051Z","iopub.execute_input":"2026-07-11T02:47:58.478299Z","iopub.status.idle":"2026-07-11T02:47:58.484775Z","shell.execute_reply.started":"2026-07-11T02:47:58.478285Z","shell.execute_reply":"2026-07-11T02:47:58.483861Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Confusion Matrix Figure\n# ============================================================\n\nplt.figure(figsize=(6,6))\n\nplt.imshow(cm, cmap=\"Blues\")\n\nplt.title(\"Confusion Matrix\")\n\nplt.colorbar()\n\nplt.xticks([0,1],[\"Class 0\",\"Class 1\"])\n\nplt.yticks([0,1],[\"Class 0\",\"Class 1\"])\n\nfor i in range(2):\n    for j in range(2):\n\n        plt.text(\n            j,\n            i,\n            cm[i,j],\n            ha=\"center\",\n            va=\"center\",\n            color=\"black\",\n            fontsize=14\n        )\n\nplt.xlabel(\"Predicted\")\n\nplt.ylabel(\"True\")\n\nplt.tight_layout()\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:58.485701Z","iopub.execute_input":"2026-07-11T02:47:58.485951Z","iopub.status.idle":"2026-07-11T02:47:58.672792Z","shell.execute_reply.started":"2026-07-11T02:47:58.485929Z","shell.execute_reply":"2026-07-11T02:47:58.671911Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# ROC Curve\n# ============================================================\n\nfpr, tpr, _ = roc_curve(\n    y_test,\n    y_prob\n)\n\nroc_auc = auc(\n    fpr,\n    tpr\n)\n\nplt.figure(figsize=(7,6))\n\nplt.plot(\n    fpr,\n    tpr,\n    linewidth=2,\n    label=f\"AUC = {roc_auc:.4f}\"\n)\n\nplt.plot(\n    [0,1],\n    [0,1],\n    \"--\"\n)\n\nplt.xlabel(\"False Positive Rate\")\n\nplt.ylabel(\"True Positive Rate\")\n\nplt.title(\"ROC Curve\")\n\nplt.legend()\n\nplt.grid(True)\n\nplt.show()\n\nprint(\"\\nFinal AUC :\", roc_auc)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:58.673596Z","iopub.execute_input":"2026-07-11T02:47:58.673922Z","iopub.status.idle":"2026-07-11T02:47:58.828169Z","shell.execute_reply.started":"2026-07-11T02:47:58.673900Z","shell.execute_reply":"2026-07-11T02:47:58.827471Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# Vérification des probabilités\n# ============================================================\n\ny_prob = model.predict(X_test).flatten()\n\nprint(\"Minimum :\", np.min(y_prob))\nprint(\"Maximum :\", np.max(y_prob))\nprint(\"Moyenne :\", np.mean(y_prob))\n\nprint(\"\\nPremières probabilités :\")\nprint(y_prob[:20])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:58.829001Z","iopub.execute_input":"2026-07-11T02:47:58.829245Z","iopub.status.idle":"2026-07-11T02:47:59.552448Z","shell.execute_reply.started":"2026-07-11T02:47:58.829223Z","shell.execute_reply":"2026-07-11T02:47:59.551883Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(12,3))\n\ntitles = [\"FLAIR\",\"T1w\",\"T1wCE\",\"T2w\"]\n\nfor i in range(4):\n\n    plt.subplot(1,4,i+1)\n\n    plt.imshow(X[0,8,:,:,i], cmap=\"gray\")\n\n    plt.title(titles[i])\n\n    plt.axis(\"off\")\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:59.555293Z","iopub.execute_input":"2026-07-11T02:47:59.555475Z","iopub.status.idle":"2026-07-11T02:47:59.791182Z","shell.execute_reply.started":"2026-07-11T02:47:59.555461Z","shell.execute_reply":"2026-07-11T02:47:59.790446Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(X.min())\nprint(X.max())\nprint(X.mean())\nprint(X.std())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-11T02:47:59.792040Z","iopub.execute_input":"2026-07-11T02:47:59.792322Z","iopub.status.idle":"2026-07-11T02:48:01.052751Z","shell.execute_reply.started":"2026-07-11T02:47:59.792296Z","shell.execute_reply":"2026-07-11T02:48:01.052022Z"}},"outputs":[],"execution_count":null}]}