{"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":"gpu","dataSources":[{"sourceId":11848,"databundleVersionId":862157,"sourceType":"competition"}],"dockerImageVersionId":31041,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\n#import numpy as np # linear algebra\n#import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport numpy as np              # For numerical operations\nimport pandas as pd             # For working with CSVs and DataFrames\nimport matplotlib.pyplot as plt # For plotting\nimport cv2                      # For image processing\nimport seaborn as sns           # For nicer plots\nfrom sklearn.utils import shuffle                # To shuffle datasets\nfrom sklearn.metrics import confusion_matrix     # To evaluate classification results\nfrom sklearn.model_selection import train_test_split # For splitting data into train/test\nimport itertools               # Useful for looping combinations (e.g., confusion matrix plotting)\nimport shutil                  # File operations like copy, move\n\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:40.967638Z","iopub.execute_input":"2025-05-25T19:31:40.967844Z","iopub.status.idle":"2025-05-25T19:31:42.623942Z","shell.execute_reply.started":"2025-05-25T19:31:40.967827Z","shell.execute_reply":"2025-05-25T19:31:42.623099Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\ndata_dir = \"/kaggle/input/histopathologic-cancer-detection\"\n\nprint(os.listdir(data_dir))\n\n# Total Samples Available\nprint('Train Images =', len(os.listdir(os.path.join(data_dir, 'train'))))\nprint('Test Images =', len(os.listdir(os.path.join(data_dir, 'test'))))\n\n# Read train labels CSV\ndf = pd.read_csv(os.path.join(data_dir, 'train_labels.csv'))\nprint('Shape of DataFrame:', df.shape)\ndf.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:42.625744Z","iopub.execute_input":"2025-05-25T19:31:42.626154Z","iopub.status.idle":"2025-05-25T19:31:48.863864Z","shell.execute_reply.started":"2025-05-25T19:31:42.626130Z","shell.execute_reply":"2025-05-25T19:31:48.863157Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TRAIN_DIR = '/kaggle/input/histopathologic-cancer-detection/train/'\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:48.864624Z","iopub.execute_input":"2025-05-25T19:31:48.864868Z","iopub.status.idle":"2025-05-25T19:31:48.868164Z","shell.execute_reply.started":"2025-05-25T19:31:48.864851Z","shell.execute_reply":"2025-05-25T19:31:48.867532Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig = plt.figure(figsize = (20,8))\nindex = 1\nfor i in np.random.randint(low = 0, high = df.shape[0], size = 10):\n    file = TRAIN_DIR + df.iloc[i]['id'] + '.tif'\n    img = cv2.imread(file)\n    ax = fig.add_subplot(2, 5, index)\n    ax.imshow(img, cmap = 'gray')\n    index = index + 1\n    color = ['green' if df.iloc[i].label == 1 else 'red'][0]\n    ax.set_title(df.iloc[i].label, fontsize = 18, color = color)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:48.868796Z","iopub.execute_input":"2025-05-25T19:31:48.868970Z","iopub.status.idle":"2025-05-25T19:31:50.331362Z","shell.execute_reply.started":"2025-05-25T19:31:48.868943Z","shell.execute_reply":"2025-05-25T19:31:50.330598Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Removing problematic images\ndf = df[df['id'] != 'dd6dfed324f9fcb6f93f46f32fc800f2ec196be2']  # corrupted image\ndf = df[df['id'] != '9369c7278ec8bcc6c880d99194de09fc2bd4efbe']  # black image\n\nprint(df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:50.332112Z","iopub.execute_input":"2025-05-25T19:31:50.332373Z","iopub.status.idle":"2025-05-25T19:31:50.392405Z","shell.execute_reply.started":"2025-05-25T19:31:50.332352Z","shell.execute_reply":"2025-05-25T19:31:50.391679Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels_count = df.label.value_counts()\n\nplt.pie(labels_count, labels=['No Cancer', 'Cancer'], startangle=180, \n        autopct='%1.1f', colors=['#00ff99','#FF96A7'], shadow=True)\nplt.figure(figsize=(16,16))\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:50.393240Z","iopub.execute_input":"2025-05-25T19:31:50.393477Z","iopub.status.idle":"2025-05-25T19:31:50.486743Z","shell.execute_reply.started":"2025-05-25T19:31:50.393452Z","shell.execute_reply":"2025-05-25T19:31:50.486218Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"SAMPLE_SIZE = 80000\n# take a random sample of class 0 with size equal to num samples in class 1\ndf_0 = df[df['label'] == 0].sample(SAMPLE_SIZE, random_state = 0)\n# filter out class 1\ndf_1 = df[df['label'] == 1].sample(SAMPLE_SIZE, random_state = 0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:50.488945Z","iopub.execute_input":"2025-05-25T19:31:50.489205Z","iopub.status.idle":"2025-05-25T19:31:50.518922Z","shell.execute_reply.started":"2025-05-25T19:31:50.489167Z","shell.execute_reply":"2025-05-25T19:31:50.518229Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# concat the dataframes\ndf_train = pd.concat([df_0, df_1], axis = 0).reset_index(drop = True)\n# shuffle\ndf_train = shuffle(df_train)\n\nprint(df_train['label'].value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:50.519761Z","iopub.execute_input":"2025-05-25T19:31:50.520490Z","iopub.status.idle":"2025-05-25T19:31:50.549586Z","shell.execute_reply.started":"2025-05-25T19:31:50.520465Z","shell.execute_reply":"2025-05-25T19:31:50.549025Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nimport os\n\n# Target labels for stratification\ny = df_train['label']\n\n# Stratified split\ndf_train, df_val = train_test_split(df_train, test_size=0.1, random_state=0, stratify=y)\n\n# Update base_dir path for Kaggle writable directory\nbase_dir = '/kaggle/working/base_dir'\ntrain_dir = os.path.join(base_dir, 'train_dir')\nval_dir = os.path.join(base_dir, 'val_dir')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:50.550222Z","iopub.execute_input":"2025-05-25T19:31:50.550391Z","iopub.status.idle":"2025-05-25T19:31:50.613179Z","shell.execute_reply.started":"2025-05-25T19:31:50.550378Z","shell.execute_reply":"2025-05-25T19:31:50.612648Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nbase_dir = '/kaggle/working/base_dir'\nos.makedirs(base_dir, exist_ok=True)  # Create base_dir if it doesn't exist\n\ntrain_dir = os.path.join(base_dir, 'train_dir')\nos.makedirs(train_dir, exist_ok=True)\n\nval_dir = os.path.join(base_dir, 'val_dir')\nos.makedirs(val_dir, exist_ok=True)\n\n# Create class subfolders inside train_dir\nos.makedirs(os.path.join(train_dir, '0'), exist_ok=True)\nos.makedirs(os.path.join(train_dir, '1'), exist_ok=True)\n\n# Create class subfolders inside val_dir\nos.makedirs(os.path.join(val_dir, '0'), exist_ok=True)\nos.makedirs(os.path.join(val_dir, '1'), exist_ok=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:50.613837Z","iopub.execute_input":"2025-05-25T19:31:50.614078Z","iopub.status.idle":"2025-05-25T19:31:50.620142Z","shell.execute_reply.started":"2025-05-25T19:31:50.614056Z","shell.execute_reply":"2025-05-25T19:31:50.619586Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(os.listdir('/kaggle/working/base_dir/train_dir'))\nprint(os.listdir('/kaggle/working/base_dir/val_dir'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:50.620750Z","iopub.execute_input":"2025-05-25T19:31:50.620955Z","iopub.status.idle":"2025-05-25T19:31:50.637675Z","shell.execute_reply.started":"2025-05-25T19:31:50.620935Z","shell.execute_reply":"2025-05-25T19:31:50.636957Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"df.set_index('id', inplace=True)\n\ntrain_list = list(df_train['id'])\nval_list = list(df_val['id'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:50.638392Z","iopub.execute_input":"2025-05-25T19:31:50.638591Z","iopub.status.idle":"2025-05-25T19:31:50.675158Z","shell.execute_reply.started":"2025-05-25T19:31:50.638567Z","shell.execute_reply":"2025-05-25T19:31:50.674500Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_dir = '/kaggle/input/histopathologic-cancer-detection'\n\nfor image in train_list:\n    file_name = image + '.tif'\n    target = df.loc[image, 'label']\n\n    label = '0' if target == 0 else '1'\n\n    src = os.path.join(data_dir, 'train', file_name)  # Kaggle input path\n    dest = os.path.join(train_dir, label, file_name)  # Kaggle working path\n\n    shutil.copyfile(src, dest)\n\nfor image in val_list:\n    file_name = image + '.tif'\n    target = df.loc[image, 'label']\n\n    label = '0' if target == 0 else '1'\n\n    src = os.path.join(data_dir, 'train', file_name)\n    dest = os.path.join(val_dir, label, file_name)\n\n    shutil.copyfile(src, dest)\n\nprint(len(os.listdir(os.path.join(train_dir, '0'))))\nprint(len(os.listdir(os.path.join(train_dir, '1'))))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:31:50.675900Z","iopub.execute_input":"2025-05-25T19:31:50.676107Z","iopub.status.idle":"2025-05-25T19:56:35.364485Z","shell.execute_reply.started":"2025-05-25T19:31:50.676091Z","shell.execute_reply":"2025-05-25T19:56:35.363840Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\nimport numpy as np\n\nIMAGE_SIZE = 96\n\ntrain_path = '/kaggle/working/base_dir/train_dir'\nvalid_path = '/kaggle/working/base_dir/val_dir'\ntest_path = '/kaggle/input/histopathologic-cancer-detection/test'\n\nnum_train_samples = len(df_train)\nnum_val_samples = len(df_val)\ntrain_batch_size = 32\nval_batch_size = 32\n\ntrain_steps = np.ceil(num_train_samples / train_batch_size)\nval_steps = np.ceil(num_val_samples / val_batch_size)\n\ndatagen = ImageDataGenerator(rescale=1.0/255)\n\ntrain_gen = datagen.flow_from_directory(\n    train_path,\n    target_size=(IMAGE_SIZE, IMAGE_SIZE),\n    batch_size=train_batch_size,\n    class_mode='categorical'\n)\n\nval_gen = datagen.flow_from_directory(\n    valid_path,\n    target_size=(IMAGE_SIZE, IMAGE_SIZE),\n    batch_size=val_batch_size,\n    class_mode='categorical'\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:56:35.365286Z","iopub.execute_input":"2025-05-25T19:56:35.365546Z","iopub.status.idle":"2025-05-25T19:56:49.283124Z","shell.execute_reply.started":"2025-05-25T19:56:35.365522Z","shell.execute_reply":"2025-05-25T19:56:49.282402Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Conv2D, Dropout, MaxPooling2D, Flatten, Dense\nfrom tensorflow.keras.layers import BatchNormalization, SeparableConv2D, Activation","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:56:49.283948Z","iopub.execute_input":"2025-05-25T19:56:49.284430Z","iopub.status.idle":"2025-05-25T19:56:49.301537Z","shell.execute_reply.started":"2025-05-25T19:56:49.284411Z","shell.execute_reply":"2025-05-25T19:56:49.301040Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Net:\n    @staticmethod\n    def build(width, height, depth, classes):\n            \n            #initializa model\n            model = Sequential()\n            \n            inputShape = (height, width, depth)\n            \n            #Add First Layer CONV => ReLU => Pooling\n            model.add(Conv2D(filters = 32, kernel_size = (5,5), padding=\"same\", activation='relu', input_shape= inputShape))\n            model.add(Conv2D(filters = 32, kernel_size = (3,3), padding=\"same\", activation='relu'))\n            model.add(Conv2D(filters = 32, kernel_size = (3,3), padding=\"same\", activation='relu'))\n            model.add(MaxPooling2D(pool_size=(2, 2)))\n            model.add(Dropout(0.2))\n            \n            #Add Second Layer CONV => ReLU => Pooling\n            model.add(Conv2D(filters = 64, kernel_size = (3,3), padding=\"same\", activation='relu'))\n            model.add(Conv2D(filters = 64, kernel_size = (3,3), padding=\"same\", activation='relu'))\n            model.add(Conv2D(filters = 64, kernel_size = (3,3), padding=\"same\", activation='relu'))\n            model.add(MaxPooling2D(pool_size=(2, 2)))\n            model.add(Dropout(0.2))\n            \n            #Add Third Layer CONV => ReLU => Pooling\n            model.add(Conv2D(filters = 128, kernel_size = (3,3), padding=\"same\", activation='relu'))\n            model.add(Conv2D(filters = 128, kernel_size = (3,3), padding=\"same\", activation='relu'))\n            model.add(Conv2D(filters = 128, kernel_size = (3,3), padding=\"same\", activation='relu'))\n            model.add(MaxPooling2D(pool_size=(2, 2)))\n            model.add(Dropout(0.25))\n            \n            #FC => ReLU\n            model.add(Flatten())\n            model.add(Dense(units = 500, activation = 'relu'))\n            model.add(Dropout(0.2))\n            #FC => Output\n            model.add(Dense(classes, activation='softmax'))\n            \n            model.summary()\n            \n            return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:56:49.302169Z","iopub.execute_input":"2025-05-25T19:56:49.302394Z","iopub.status.idle":"2025-05-25T19:56:49.321592Z","shell.execute_reply.started":"2025-05-25T19:56:49.302380Z","shell.execute_reply":"2025-05-25T19:56:49.320940Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = Net.build(width = 96, height = 96, depth = 3, classes = 2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:56:49.322240Z","iopub.execute_input":"2025-05-25T19:56:49.322461Z","iopub.status.idle":"2025-05-25T19:56:51.739739Z","shell.execute_reply.started":"2025-05-25T19:56:49.322447Z","shell.execute_reply":"2025-05-25T19:56:51.739144Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.optimizers import Adam\n\nmodel.compile(optimizer=Adam(learning_rate=0.0001), \n              loss='categorical_crossentropy', \n              metrics=['accuracy'])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:56:51.740462Z","iopub.execute_input":"2025-05-25T19:56:51.740908Z","iopub.status.idle":"2025-05-25T19:56:51.754807Z","shell.execute_reply.started":"2025-05-25T19:56:51.740882Z","shell.execute_reply":"2025-05-25T19:56:51.754180Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau\n\nfilepath = \"checkpoint.h5\"\ncheckpoint = ModelCheckpoint(filepath, monitor='val_accuracy', verbose=1, \n                             save_best_only=True, mode='max')\n\nreduce_lr = ReduceLROnPlateau(monitor='val_accuracy', factor=0.5, patience=2, \n                              verbose=1, mode='max', min_lr=1e-5)\n\ncallbacks_list = [checkpoint, reduce_lr]\n\ntrain_steps = int(np.ceil(num_train_samples / train_batch_size))\nval_steps = int(np.ceil(num_val_samples / val_batch_size))\n\nhistory = model.fit(\n    train_gen,\n    steps_per_epoch=train_steps,\n    validation_data=val_gen,\n    validation_steps=val_steps,\n    epochs=11,\n    verbose=1,\n    callbacks=callbacks_list\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T19:56:51.755468Z","iopub.execute_input":"2025-05-25T19:56:51.755758Z","iopub.status.idle":"2025-05-25T20:16:57.979477Z","shell.execute_reply.started":"2025-05-25T19:56:51.755741Z","shell.execute_reply":"2025-05-25T20:16:57.978872Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Plot training & validation accuracy values\n\nplt.plot(history.history['accuracy'])       # instead of 'acc'\nplt.plot(history.history['val_accuracy'])   # instead of 'val_acc'\nplt.title('Model accuracy')\nplt.ylabel('Accuracy')\nplt.xlabel('Epoch')\nplt.legend(['Train', 'Validation'], loc='best')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T20:16:57.980599Z","iopub.execute_input":"2025-05-25T20:16:57.980858Z","iopub.status.idle":"2025-05-25T20:16:58.155014Z","shell.execute_reply.started":"2025-05-25T20:16:57.980840Z","shell.execute_reply":"2025-05-25T20:16:58.154473Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Plot training & validation loss values\nplt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.title('Model loss')\nplt.ylabel('Loss')\nplt.xlabel('Epoch')\nplt.legend(['Train', 'Test'], loc='best')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T20:16:58.155673Z","iopub.execute_input":"2025-05-25T20:16:58.155902Z","iopub.status.idle":"2025-05-25T20:16:58.309231Z","shell.execute_reply.started":"2025-05-25T20:16:58.155885Z","shell.execute_reply":"2025-05-25T20:16:58.308594Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\nIMAGE_SIZE = 96\nval_batch_size = 32\nvalid_path = '/kaggle/working/base_dir/val_dir'\n\n# Rescale pixel values\ndatagen = ImageDataGenerator(rescale=1.0 / 255)\n\n# Define the validation generator\nval_gen = datagen.flow_from_directory(\n    valid_path,\n    target_size=(IMAGE_SIZE, IMAGE_SIZE),\n    batch_size=val_batch_size,\n    class_mode='categorical',\n    shuffle=False  # IMPORTANT for correct label alignment\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T20:16:58.312101Z","iopub.execute_input":"2025-05-25T20:16:58.312317Z","iopub.status.idle":"2025-05-25T20:16:58.453745Z","shell.execute_reply.started":"2025-05-25T20:16:58.312301Z","shell.execute_reply":"2025-05-25T20:16:58.453244Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load best weights\nmodel.load_weights('checkpoint.h5')\n\n# Evaluate using the generator\nval_loss, val_acc = model.evaluate(val_gen, steps=val_steps, verbose=1)\nprint('val_loss:', val_loss)\nprint('val_acc:', val_acc)\n\n# Predict using the generator\npredictions = model.predict(val_gen, steps=val_steps, verbose=1)\n\n# Convert predictions to DataFrame\ndf_preds = pd.DataFrame(predictions, columns=['no_tumor', 'has_tumor'])\ndf_preds.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T20:16:58.454386Z","iopub.execute_input":"2025-05-25T20:16:58.454587Z","iopub.status.idle":"2025-05-25T20:17:18.203047Z","shell.execute_reply.started":"2025-05-25T20:16:58.454572Z","shell.execute_reply":"2025-05-25T20:17:18.202476Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# y_true: True labels (0 or 1)\ny_true = val_gen.classes  # This is an array like [0, 1, 0, 0, 1, ...]\n\n# y_pred: Predicted probabilities for class 1 (has_tumor)\n# predictions is of shape (num_samples, 2) from model.predict\ny_pred = predictions[:, 1]  # Probability of 'has_tumor'\n\nfrom sklearn.metrics import roc_auc_score, roc_curve, auc\nimport matplotlib.pyplot as plt\n\n# Compute ROC AUC Score\nroc_auc = roc_auc_score(y_true, y_pred)\nprint('ROC AUC Score =', roc_auc)\n\n# Compute ROC Curve values\nfpr, tpr, thresholds = roc_curve(y_true, y_pred)\nroc_auc_val = auc(fpr, tpr)\n\n# Plot ROC Curve\nplt.figure(figsize=(8, 6))\nplt.plot([0, 1], [0, 1], 'k--')\nplt.plot(fpr, tpr, label=f'AUC = {roc_auc_val:.2f}')\nplt.xlabel('False Positive Rate')\nplt.ylabel('True Positive Rate')\nplt.title('ROC Curve')\nplt.legend(loc='best')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T20:17:18.203815Z","iopub.execute_input":"2025-05-25T20:17:18.204081Z","iopub.status.idle":"2025-05-25T20:17:18.374886Z","shell.execute_reply.started":"2025-05-25T20:17:18.204064Z","shell.execute_reply":"2025-05-25T20:17:18.374245Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix, classification_report\nfrom mlxtend.plotting import plot_confusion_matrix\nimport matplotlib.pyplot as plt\n\ny_pred_binary = predictions.argmax(axis=1)\ncm = confusion_matrix(y_true, y_pred_binary)\n\nfig, ax = plot_confusion_matrix(conf_mat=cm,\n                                show_absolute=True,\n                                show_normed=True,\n                                colorbar=True,\n                                cmap='Dark2')\nplt.show()\n\nreport = classification_report(y_true, y_pred_binary, target_names=['no_tumor', 'has_tumor'])\nprint(report)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T20:17:18.375518Z","iopub.execute_input":"2025-05-25T20:17:18.375713Z","iopub.status.idle":"2025-05-25T20:17:18.687141Z","shell.execute_reply.started":"2025-05-25T20:17:18.375698Z","shell.execute_reply":"2025-05-25T20:17:18.686557Z"}},"outputs":[],"execution_count":null}]}