{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"from pathlib import Path\n\ninput_root = Path(\"/kaggle/input\")\n\nprint(\"Kaggle input datasets:\")\nfor item in input_root.iterdir():\n    print(f\"{'DIR ' if item.is_dir() else 'FILE'} {item}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:30:40.349644Z","iopub.execute_input":"2026-09-14T06:30:40.35008Z","iopub.status.idle":"2026-09-14T06:30:40.366189Z","shell.execute_reply.started":"2026-09-14T06:30:40.35003Z","shell.execute_reply":"2026-09-14T06:30:40.364821Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pathlib import Path\n\nCOMP_DIR = next(Path(\"/kaggle/input/competitions\").iterdir())\n\nprint(f\"Competition directory: {COMP_DIR}\")\nprint(\"\\nTop-level contents:\")\n\nfor item in COMP_DIR.iterdir():\n    print(f\"{'DIR ' if item.is_dir() else 'FILE'}  {item.name}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:30:40.369348Z","iopub.execute_input":"2026-09-14T06:30:40.369857Z","iopub.status.idle":"2026-09-14T06:30:40.396064Z","shell.execute_reply.started":"2026-09-14T06:30:40.369806Z","shell.execute_reply":"2026-09-14T06:30:40.39464Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Discover and load all CSV files\ncsv_files = {\n    file.stem: file\n    for file in COMP_DIR.iterdir()\n    if file.is_file() and file.suffix.lower() == \".csv\"\n}\n\nprint(\"Discovered CSV files:\")\nfor name in sorted(csv_files):\n    print(f\"  {name}.csv\")\n\ndataframes = {\n    name: pd.read_csv(path)\n    for name, path in csv_files.items()\n}\n\nprint(\"\\n===== DATASET SHAPES =====\")\nfor name, df in dataframes.items():\n    print(f\"{name:20s}: {df.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:30:40.397481Z","iopub.execute_input":"2026-09-14T06:30:40.397828Z","iopub.status.idle":"2026-09-14T06:30:42.671051Z","shell.execute_reply.started":"2026-09-14T06:30:40.397794Z","shell.execute_reply":"2026-09-14T06:30:42.669553Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"===== TRAIN =====\")\n\ntrain_df = next(\n    df for df in dataframes.values()\n    if \"Report\" in df.columns\n    and \"StudyInstanceUID\" in df.columns\n)\n\ndisplay(train_df.head())\nprint(\"Columns:\", train_df.columns.tolist())\n\n\nprint(\"\\n===== TRAIN SERIES =====\")\n\nseries_candidates = [\n    df for df in dataframes.values()\n    if {\n        \"StudyInstanceUID\",\n        \"SeriesInstanceUID\",\n        \"Fluid_Sensitive\",\n        \"Anatomical_Plane\"\n    }.issubset(df.columns)\n]\n\ntrain_series = max(series_candidates, key=len)\n\ndisplay(train_series.head())\nprint(\"Columns:\", train_series.columns.tolist())\n\n\nprint(\"\\n===== TEST =====\")\n\ntest_df = next(\n    df for df in dataframes.values()\n    if list(df.columns) == [\"StudyInstanceUID\"]\n)\n\ndisplay(test_df.head())\nprint(\"Columns:\", test_df.columns.tolist())\n\n\nprint(\"\\n===== SAMPLE SUBMISSION =====\")\n\nsample_submission = next(\n    df for df in dataframes.values()\n    if \"StudyInstanceUID\" in df.columns\n    and len(df.columns) == 13\n)\n\ndisplay(sample_submission.head())\nprint(\"Columns:\", sample_submission.columns.tolist())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:31:47.891664Z","iopub.execute_input":"2026-09-14T06:31:47.892095Z","iopub.status.idle":"2026-09-14T06:31:48.004015Z","shell.execute_reply.started":"2026-09-14T06:31:47.892059Z","shell.execute_reply":"2026-09-14T06:31:48.00232Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TARGET_COLS = [\n    col for col in sample_submission.columns\n    if col != \"StudyInstanceUID\"\n]\n\nprint(f\"Number of targets: {len(TARGET_COLS)}\")\nprint(\"\\nTargets:\")\nfor i, col in enumerate(TARGET_COLS, 1):\n    print(f\"{i:2}. {col}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:31:52.794366Z","iopub.execute_input":"2026-09-14T06:31:52.79479Z","iopub.status.idle":"2026-09-14T06:31:52.802859Z","shell.execute_reply.started":"2026-09-14T06:31:52.794748Z","shell.execute_reply":"2026-09-14T06:31:52.800941Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"===== LABEL AVAILABILITY =====\")\n\nlabel_counts = train_df[TARGET_COLS].notna().sum()\n\ndisplay(\n    pd.DataFrame({\n        \"Labeled\": label_counts,\n        \"Missing\": len(train_df) - label_counts\n    })\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:31:54.070844Z","iopub.execute_input":"2026-09-14T06:31:54.071299Z","iopub.status.idle":"2026-09-14T06:31:54.093505Z","shell.execute_reply.started":"2026-09-14T06:31:54.07125Z","shell.execute_reply":"2026-09-14T06:31:54.092204Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labeled_df = train_df[train_df[TARGET_COLS].notna().all(axis=1)].copy()\n\nlabel_summary = pd.DataFrame({\n    \"Positive\": labeled_df[TARGET_COLS].sum(),\n    \"Negative\": (1 - labeled_df[TARGET_COLS]).sum(),\n    \"Positive %\": labeled_df[TARGET_COLS].mean() * 100\n}).round(2)\n\ndisplay(label_summary)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:31:54.745972Z","iopub.execute_input":"2026-09-14T06:31:54.746401Z","iopub.status.idle":"2026-09-14T06:31:54.76991Z","shell.execute_reply.started":"2026-09-14T06:31:54.746366Z","shell.execute_reply":"2026-09-14T06:31:54.768631Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Labeled studies:\", len(labeled_df))\n\ndisplay(\n    labeled_df[[\"StudyInstanceUID\"] + TARGET_COLS].reset_index(drop=True)\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:31:58.288153Z","iopub.execute_input":"2026-09-14T06:31:58.289193Z","iopub.status.idle":"2026-09-14T06:31:58.371152Z","shell.execute_reply.started":"2026-09-14T06:31:58.289131Z","shell.execute_reply":"2026-09-14T06:31:58.369614Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Correlation between the 12 abnormalities\nlabel_corr = labeled_df[TARGET_COLS].corr()\n\ndisplay(label_corr.round(2))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:29.93653Z","iopub.execute_input":"2026-09-14T06:32:29.936922Z","iopub.status.idle":"2026-09-14T06:32:29.974673Z","shell.execute_reply.started":"2026-09-14T06:32:29.936889Z","shell.execute_reply":"2026-09-14T06:32:29.972919Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport seaborn as sns\n\nplt.figure(figsize=(12, 9))\n\nsns.heatmap(\n    label_corr,\n    annot=True,\n    fmt=\".2f\",\n    cmap=\"coolwarm\",\n    center=0,\n    square=True\n)\n\nplt.title(\"Correlation Between Abnormality Labels\")\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:30.297589Z","iopub.execute_input":"2026-09-14T06:32:30.298145Z","iopub.status.idle":"2026-09-14T06:32:32.571208Z","shell.execute_reply.started":"2026-09-14T06:32:30.298097Z","shell.execute_reply":"2026-09-14T06:32:32.569766Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Find the dataframe containing series-level information\nseries_df = next(\n    df for df in dataframes.values()\n    if {\"StudyInstanceUID\", \"SeriesInstanceUID\"}.issubset(df.columns)\n)\n\n# Number of series per study\nseries_per_study = series_df.groupby(\"StudyInstanceUID\").size()\n\nprint(\"Series per study:\")\ndisplay(series_per_study.describe().round(2))\n\nprint(\"\\nMost common series counts:\")\ndisplay(series_per_study.value_counts().sort_index().head(20))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:41.94016Z","iopub.execute_input":"2026-09-14T06:32:41.940731Z","iopub.status.idle":"2026-09-14T06:32:41.978716Z","shell.execute_reply.started":"2026-09-14T06:32:41.940696Z","shell.execute_reply":"2026-09-14T06:32:41.976691Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"series_candidates = [\n    df for df in dataframes.values()\n    if {\"StudyInstanceUID\", \"SeriesInstanceUID\"}.issubset(df.columns)\n]\n\nfor i, df in enumerate(series_candidates):\n    print(f\"Candidate {i}: {df.shape}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:42.274929Z","iopub.execute_input":"2026-09-14T06:32:42.27533Z","iopub.status.idle":"2026-09-14T06:32:42.282485Z","shell.execute_reply.started":"2026-09-14T06:32:42.275297Z","shell.execute_reply":"2026-09-14T06:32:42.281111Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Selected series dataframe:\", series_df.shape)\n\nprint(\"\\nColumns:\")\nfor col in series_df.columns:\n    print(f\" - {col}\")\n\nprint(\"\\nUnique values:\")\nfor col in [\"Fluid_Sensitive\", \"Fat_Suppression\", \"Anatomical_Plane\"]:\n    print(f\"\\n{col}:\")\n    display(series_df[col].value_counts(dropna=False))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:44.377056Z","iopub.execute_input":"2026-09-14T06:32:44.377485Z","iopub.status.idle":"2026-09-14T06:32:44.403107Z","shell.execute_reply.started":"2026-09-14T06:32:44.377452Z","shell.execute_reply":"2026-09-14T06:32:44.401198Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\n    \"Fluid_Sensitive == Fat_Suppression:\",\n    (series_df[\"Fluid_Sensitive\"] == series_df[\"Fat_Suppression\"]).all()\n)\n\nprint(\"\\nUnique combinations:\")\ndisplay(\n    series_df[\n        [\"Fluid_Sensitive\", \"Fat_Suppression\"]\n    ].value_counts().rename(\"Count\").reset_index()\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:44.612956Z","iopub.execute_input":"2026-09-14T06:32:44.613401Z","iopub.status.idle":"2026-09-14T06:32:44.639628Z","shell.execute_reply.started":"2026-09-14T06:32:44.613367Z","shell.execute_reply":"2026-09-14T06:32:44.637988Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"display(\n    pd.crosstab(\n        series_df[\"Anatomical_Plane\"],\n        series_df[\"Fluid_Sensitive\"],\n        normalize=\"index\"\n    ).round(3)\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:47.260498Z","iopub.execute_input":"2026-09-14T06:32:47.26091Z","iopub.status.idle":"2026-09-14T06:32:47.298309Z","shell.execute_reply.started":"2026-09-14T06:32:47.260875Z","shell.execute_reply":"2026-09-14T06:32:47.29722Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"study_plane_counts = pd.crosstab(\n    series_df[\"StudyInstanceUID\"],\n    series_df[\"Anatomical_Plane\"]\n)\n\ndisplay(study_plane_counts.describe().round(2))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:47.630691Z","iopub.execute_input":"2026-09-14T06:32:47.631094Z","iopub.status.idle":"2026-09-14T06:32:47.664634Z","shell.execute_reply.started":"2026-09-14T06:32:47.631061Z","shell.execute_reply":"2026-09-14T06:32:47.663561Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"series_counts = series_df.groupby(\"StudyInstanceUID\").size()\n\ndisplay(series_counts.describe().round(2))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:50.650577Z","iopub.execute_input":"2026-09-14T06:32:50.650963Z","iopub.status.idle":"2026-09-14T06:32:50.664528Z","shell.execute_reply.started":"2026-09-14T06:32:50.650931Z","shell.execute_reply":"2026-09-14T06:32:50.662667Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"display(\n    pd.crosstab(\n        series_df[\"Anatomical_Plane\"],\n        series_df[\"Fluid_Sensitive\"]\n    )\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:50.941611Z","iopub.execute_input":"2026-09-14T06:32:50.942031Z","iopub.status.idle":"2026-09-14T06:32:50.966362Z","shell.execute_reply.started":"2026-09-14T06:32:50.941996Z","shell.execute_reply":"2026-09-14T06:32:50.963757Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pydicom\nimport matplotlib.pyplot as plt\n\n# Pick the first fully labeled study\nstudy_id = labeled_df[\"StudyInstanceUID\"].iloc[0]\n\n# Find its series\nstudy_series = series_df[\n    series_df[\"StudyInstanceUID\"] == study_id\n]\n\ndisplay(study_series)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:52.737128Z","iopub.execute_input":"2026-09-14T06:32:52.737566Z","iopub.status.idle":"2026-09-14T06:32:53.809644Z","shell.execute_reply.started":"2026-09-14T06:32:52.737531Z","shell.execute_reply":"2026-09-14T06:32:53.808302Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Find directories inside the competition folder that contain DICOM files\ndcm_dirs = []\n\nfor item in COMP_DIR.iterdir():\n    if item.is_dir():\n        dcm_dirs.append(item)\n\nprint(\"Top-level directories:\")\nfor d in dcm_dirs:\n    print(d)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:53.811628Z","iopub.execute_input":"2026-09-14T06:32:53.811995Z","iopub.status.idle":"2026-09-14T06:32:53.825857Z","shell.execute_reply.started":"2026-09-14T06:32:53.811965Z","shell.execute_reply":"2026-09-14T06:32:53.824296Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Find the training DICOM directory dynamically\ntrain_dcm_dir = next(\n    d for d in dcm_dirs\n    if d.name == \"train_series\"\n)\n\n# Find the selected study directory\nstudy_dir = next(\n    d for d in train_dcm_dir.iterdir()\n    if d.name == study_id\n)\n\nprint(\"Study directory:\", study_dir)\n\n# Show its series directories\nseries_dirs = [d for d in study_dir.iterdir() if d.is_dir()]\n\nprint(\"Number of series folders:\", len(series_dirs))\nfor d in series_dirs:\n    print(d.name)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:55.217785Z","iopub.execute_input":"2026-09-14T06:32:55.218642Z","iopub.status.idle":"2026-09-14T06:32:55.32462Z","shell.execute_reply.started":"2026-09-14T06:32:55.218594Z","shell.execute_reply":"2026-09-14T06:32:55.323255Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for series_dir in series_dirs:\n    dcm_files = [f for f in series_dir.iterdir() if f.is_file()]\n    print(f\"{series_dir.name}: {len(dcm_files)} DICOM files\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:57.391368Z","iopub.execute_input":"2026-09-14T06:32:57.391758Z","iopub.status.idle":"2026-09-14T06:32:57.438614Z","shell.execute_reply.started":"2026-09-14T06:32:57.391727Z","shell.execute_reply":"2026-09-14T06:32:57.437325Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pydicom\nimport matplotlib.pyplot as plt\n\n# Pick the first series\nselected_series = series_dirs[0]\n\n# Get DICOM files dynamically\ndcm_files = sorted(\n    [f for f in selected_series.iterdir() if f.is_file()]\n)\n\n# Read 3 slices: beginning, middle, end\nindices = [0, len(dcm_files)//2, len(dcm_files)-1]\n\nfig, axes = plt.subplots(1, 3, figsize=(15, 5))\n\nfor ax, idx in zip(axes, indices):\n    ds = pydicom.dcmread(dcm_files[idx])\n    ax.imshow(ds.pixel_array, cmap=\"gray\")\n    ax.set_title(f\"Slice {idx}\")\n    ax.axis(\"off\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:32:57.683666Z","iopub.execute_input":"2026-09-14T06:32:57.684046Z","iopub.status.idle":"2026-09-14T06:32:58.523916Z","shell.execute_reply.started":"2026-09-14T06:32:57.684014Z","shell.execute_reply":"2026-09-14T06:32:58.52255Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for idx in [0, len(dcm_files)//2, len(dcm_files)-1]:\n    ds = pydicom.dcmread(dcm_files[idx])\n    print(\n        f\"File index: {idx} | \"\n        f\"InstanceNumber: {getattr(ds, 'InstanceNumber', 'N/A')} | \"\n        f\"Rows: {ds.Rows} | Columns: {ds.Columns}\"\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:33:00.671881Z","iopub.execute_input":"2026-09-14T06:33:00.672388Z","iopub.status.idle":"2026-09-14T06:33:00.691485Z","shell.execute_reply.started":"2026-09-14T06:33:00.672321Z","shell.execute_reply":"2026-09-14T06:33:00.689611Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Read all slices and inspect their InstanceNumber\nslice_info = []\n\nfor f in dcm_files:\n    ds = pydicom.dcmread(f, stop_before_pixels=True)\n    slice_info.append({\n        \"file\": f,\n        \"InstanceNumber\": getattr(ds, \"InstanceNumber\", None)\n    })\n\nslice_info_df = pd.DataFrame(slice_info)\n\ndisplay(\n    slice_info_df.sort_values(\"InstanceNumber\").reset_index(drop=True)\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:33:03.070327Z","iopub.execute_input":"2026-09-14T06:33:03.070822Z","iopub.status.idle":"2026-09-14T06:33:03.429739Z","shell.execute_reply.started":"2026-09-14T06:33:03.070783Z","shell.execute_reply":"2026-09-14T06:33:03.428755Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ds = pydicom.dcmread(slice_info_df.iloc[len(slice_info_df)//2][\"file\"])\n\npixels = ds.pixel_array\n\nprint(\"Shape:\", pixels.shape)\nprint(\"Dtype:\", pixels.dtype)\nprint(\"Min:\", pixels.min())\nprint(\"Max:\", pixels.max())\nprint(\"Mean:\", pixels.mean())\nprint(\"Std:\", pixels.std())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:33:03.45925Z","iopub.execute_input":"2026-09-14T06:33:03.459673Z","iopub.status.idle":"2026-09-14T06:33:03.474188Z","shell.execute_reply.started":"2026-09-14T06:33:03.459638Z","shell.execute_reply":"2026-09-14T06:33:03.473047Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img = pixels.astype(\"float32\")\n\n# Per-image min-max normalization\nimg_norm = (img - img.min()) / (img.max() - img.min() + 1e-8)\n\nfig, axes = plt.subplots(1, 2, figsize=(10, 5))\n\naxes[0].imshow(img, cmap=\"gray\")\naxes[0].set_title(\"Original\")\naxes[0].axis(\"off\")\n\naxes[1].imshow(img_norm, cmap=\"gray\")\naxes[1].set_title(\"Min-Max Normalized\")\naxes[1].axis(\"off\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-14T06:33:05.76395Z","iopub.execute_input":"2026-09-14T06:33:05.76438Z","iopub.status.idle":"2026-09-14T06:33:06.226664Z","shell.execute_reply.started":"2026-09-14T06:33:05.764346Z","shell.execute_reply":"2026-09-14T06:33:06.225416Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}