{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.13.15","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":"\nimport os\nimport tensorflow as tf\nimport numpy as np\nimport pandas as pd\n\nprint(\"TensorFlow Version:\", tf.__version__)\nprint(\"GPU Available:\", tf.config.list_physical_devices(\"GPU\"))\nprint(\"NumPy Version:\", np.__version__)\nprint(\"Pandas Version:\", pd.__version__)\n\nprint(\"\\nAVAILABLE DATASET FILES:\")\nfor root, dirs, files in os.walk(\"/kaggle/input\"):\n    for file in files[:10]:\n        print(os.path.join(root, file))\n    if root.count(os.sep) > 5:\n        dirs[:] = []\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:02:43.49475Z","iopub.execute_input":"2026-10-11T14:02:43.495155Z","iopub.status.idle":"2026-10-11T14:03:02.534692Z","shell.execute_reply.started":"2026-10-11T14:02:43.495127Z","shell.execute_reply":"2026-10-11T14:03:02.533855Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 1 — Environment and Dataset Verification\n\nHumne TensorFlow, NumPy aur Pandas libraries import ki aur Kaggle GPU availability check ki. Saath hi dataset files ke paths identify kiye.\nDevelopment environment verify kiya aur GPU check kiya taake RNN/LSTM models efficiently train ho sakein.\n","metadata":{}},{"cell_type":"code","source":"\nimport zipfile\nimport os\n\nDATA_DIR = \"/kaggle/input/competitions/grasp-and-lift-eeg-detection\"\n\nzip_files = [\n    \"train.zip\",\n    \"test.zip\",\n    \"sample_submission.csv.zip\"\n]\n\nfor filename in zip_files:\n    path = os.path.join(DATA_DIR, filename)\n\n    with zipfile.ZipFile(path, \"r\") as z:\n        files = z.infolist()\n\n        print(f\"\\n{'='*55}\")\n        print(\"ZIP File:\", filename)\n        print(\"Total Files:\", len(files))\n        print(\"Uncompressed Size (GB):\",\n              round(sum(f.file_size for f in files) / (1024**3), 3))\n\n        print(\"\\nFirst 10 Files:\")\n        for f in files[:10]:\n            print(\" -\", f.filename)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:03:02.536179Z","iopub.execute_input":"2026-10-11T14:03:02.536771Z","iopub.status.idle":"2026-10-11T14:03:02.561205Z","shell.execute_reply.started":"2026-10-11T14:03:02.536746Z","shell.execute_reply":"2026-10-11T14:03:02.560557Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 2 — Dataset Structure Inspection\n\nHumne sabse pehle dataset structure analyze kiya taake EEG training files, testing files aur submission format identify kar sakein. Is se efficient data loading strategy decide karne mein help milti hai.\n","metadata":{}},{"cell_type":"code","source":"\nimport zipfile\nimport pandas as pd\n\ntrain_zip = f\"{DATA_DIR}/train.zip\"\nsubmission_zip = f\"{DATA_DIR}/sample_submission.csv.zip\"\n\nwith zipfile.ZipFile(train_zip) as z:\n    data_file = next(\n        n for n in z.namelist()\n        if n.endswith(\"_data.csv\")\n    )\n    event_file = data_file.replace(\"_data.csv\", \"_events.csv\")\n\n    with z.open(data_file) as f:\n        eeg_sample = pd.read_csv(f, nrows=5)\n\n    with z.open(event_file) as f:\n        event_sample = pd.read_csv(f, nrows=5)\n\nwith zipfile.ZipFile(submission_zip) as z:\n    with z.open(\"sample_submission.csv\") as f:\n        submission_sample = pd.read_csv(f, nrows=5)\n\nprint(\"EEG FILE:\", data_file)\nprint(\"EEG Shape:\", eeg_sample.shape)\nprint(\"EEG Columns:\", eeg_sample.columns.tolist())\ndisplay(eeg_sample)\n\nprint(\"\\nEVENT FILE:\", event_file)\nprint(\"Event Shape:\", event_sample.shape)\nprint(\"Event Columns:\", event_sample.columns.tolist())\ndisplay(event_sample)\n\nprint(\"\\nSAMPLE SUBMISSION:\")\nprint(\"Columns:\", submission_sample.columns.tolist())\ndisplay(submission_sample)\n\nprint(\"\\nEEG and Event IDs Match:\",\n      eeg_sample[\"id\"].equals(event_sample[\"id\"]))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:03:02.562909Z","iopub.execute_input":"2026-10-11T14:03:02.563242Z","iopub.status.idle":"2026-10-11T14:03:02.673776Z","shell.execute_reply.started":"2026-10-11T14:03:02.563221Z","shell.execute_reply":"2026-10-11T14:03:02.673174Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 3 — EEG Channels, Event Labels and Submission Format\n\nHumne dataset ke features aur target labels identify kiye. EEG signals model ke inputs honge aur six movement events outputs honge. Humne IDs verify kiye taake input signals aur labels correctly aligned hon.\n","metadata":{}},{"cell_type":"code","source":"\nimport zipfile\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nEVENT_COLS = [\n    \"HandStart\",\n    \"FirstDigitTouch\",\n    \"BothStartLoadPhase\",\n    \"LiftOff\",\n    \"Replace\",\n    \"BothReleased\"\n]\n\nrecords = []\n\nwith zipfile.ZipFile(train_zip) as z:\n    event_files = sorted(\n        f for f in z.namelist()\n        if f.endswith(\"_events.csv\")\n    )\n\n    for filename in event_files:\n        with z.open(filename) as f:\n            df = pd.read_csv(\n                f,\n                usecols=EVENT_COLS,\n                dtype=\"uint8\"\n            )\n\n        counts = df[EVENT_COLS].sum()\n\n        records.append({\n            \"File\": filename,\n            \"Rows\": len(df),\n            **counts.to_dict()\n        })\n\nevent_summary = pd.DataFrame(records)\n\ntotal_rows = int(event_summary[\"Rows\"].sum())\npositive_counts = event_summary[EVENT_COLS].sum()\n\nclass_distribution = pd.DataFrame({\n    \"Positive\": positive_counts,\n    \"Negative\": total_rows - positive_counts,\n    \"Positive (%)\": positive_counts / total_rows * 100\n})\n\nprint(\"Total Training Files:\", len(event_files))\nprint(\"Total EEG Time Points:\", f\"{total_rows:,}\")\n\ndisplay(class_distribution.round(3))\n\nplt.figure(figsize=(11, 5))\nplt.bar(\n    class_distribution.index,\n    class_distribution[\"Positive (%)\"]\n)\nplt.title(\"Positive Event Distribution\")\nplt.ylabel(\"Positive Samples (%)\")\nplt.xlabel(\"Movement Events\")\nplt.xticks(rotation=30, ha=\"right\")\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:03:02.675238Z","iopub.execute_input":"2026-10-11T14:03:02.675542Z","iopub.status.idle":"2026-10-11T14:03:12.081753Z","shell.execute_reply.started":"2026-10-11T14:03:02.67552Z","shell.execute_reply":"2026-10-11T14:03:12.081076Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 4 — Event Distribution and Class Imbalance Analysis\n\nHumne exploratory data analysis mein event distribution check kiya. Is analysis se pata chalta hai ke minority events kitne rare hain aur training ke waqt class imbalance handling ki kitni zarurat hai.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport zipfile\n\nwith zipfile.ZipFile(train_zip) as z:\n    with z.open(data_file) as f:\n        eeg_eda = pd.read_csv(f, nrows=10000)\n\n    with z.open(event_file) as f:\n        events_eda = pd.read_csv(f, nrows=10000)\n\nEEG_COLS = [c for c in eeg_eda.columns if c != \"id\"]\n\nprint(\"Sample Shape:\", eeg_eda.shape)\nprint(\"EEG Channels:\", len(EEG_COLS))\n\nprint(\"\\nMissing Values:\")\nprint(eeg_eda.isnull().sum().sum())\n\nprint(\"\\nDuplicate IDs:\")\nprint(eeg_eda[\"id\"].duplicated().sum())\n\nprint(\"\\nEEG Statistics:\")\ndisplay(\n    eeg_eda[EEG_COLS]\n    .describe()\n    .loc[[\"mean\", \"std\", \"min\", \"max\"]]\n    .round(2)\n)\n\nprint(\"\\nSample EEG Signal Visualization:\")\n\nplt.figure(figsize=(13, 5))\n\nfor channel in [\"Fp1\", \"Fz\", \"Cz\", \"O1\"]:\n    plt.plot(\n        eeg_eda[channel].iloc[:1000].values,\n        label=channel,\n        alpha=0.8\n    )\n\nplt.title(\"EEG Signals — First 1000 Time Points\")\nplt.xlabel(\"Time Point\")\nplt.ylabel(\"EEG Signal Value\")\nplt.legend()\nplt.grid(alpha=0.2)\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:03:12.082768Z","iopub.execute_input":"2026-10-11T14:03:12.083112Z","iopub.status.idle":"2026-10-11T14:03:12.459113Z","shell.execute_reply.started":"2026-10-11T14:03:12.08309Z","shell.execute_reply":"2026-10-11T14:03:12.45828Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 5 — EEG Data Quality and Signal Visualization\n\nHumne EEG signals ka exploratory analysis kiya. Humne missing values, duplicates, mean, standard deviation aur signal variations analyze kiye taake model training ke liye appropriate preprocessing select kar sakein.\n","metadata":{}},{"cell_type":"code","source":"\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport numpy as np\n\n# 1. EEG Channel Correlation Heatmap\ncorrelation = eeg_eda[EEG_COLS].corr()\n\nplt.figure(figsize=(12, 9))\nsns.heatmap(\n    correlation,\n    cmap=\"coolwarm\",\n    center=0,\n    vmin=-1,\n    vmax=1\n)\nplt.title(\"EEG Channel Correlation Heatmap\")\nplt.tight_layout()\nplt.show()\n\n# 2. Event Timeline\nevent_matrix = events_eda[EVENT_COLS].to_numpy()\n\nprint(\"Positive event counts in sample:\")\nprint(events_eda[EVENT_COLS].sum())\n\nplt.figure(figsize=(14, 5))\n\nplt.imshow(\n    event_matrix.T,\n    aspect=\"auto\",\n    interpolation=\"nearest\",\n    cmap=\"Purples\",\n    vmin=0,\n    vmax=1\n)\n\nplt.yticks(\n    range(len(EVENT_COLS)),\n    EVENT_COLS\n)\nplt.xlabel(\"EEG Time Point\")\nplt.ylabel(\"Movement Event\")\nplt.title(\"Movement Event Timeline — Sample Recording\")\nplt.colorbar(label=\"Event Active (0/1)\")\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:03:12.460189Z","iopub.execute_input":"2026-10-11T14:03:12.460887Z","iopub.status.idle":"2026-10-11T14:03:13.55687Z","shell.execute_reply.started":"2026-10-11T14:03:12.460857Z","shell.execute_reply":"2026-10-11T14:03:13.556031Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 6 — EEG Correlation Heatmap and Event Timeline\n\nHumne correlation analysis se EEG channels ke relationships examine kiye aur event timeline se movement events ki temporal distribution samjhi. Ye analysis RNN/LSTM models ke liye important hai kyunki ye models sequential patterns learn karte hain.\n","metadata":{}},{"cell_type":"code","source":"\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport re\n\nsubject_summary = event_summary.copy()\n\nsubject_summary[\"Subject\"] = subject_summary[\"File\"].apply(\n    lambda x: re.search(r\"subj(\\d+)\", x).group(1)\n)\n\nsubject_summary[\"Subject\"] = (\n    subject_summary[\"Subject\"].astype(int)\n)\n\nsubject_counts = (\n    subject_summary.groupby(\"Subject\")[EVENT_COLS]\n    .sum()\n    .sort_index()\n)\n\nsubject_percentages = (\n    subject_summary.groupby(\"Subject\")[EVENT_COLS]\n    .sum()\n    .div(\n        subject_summary.groupby(\"Subject\")[\"Rows\"].sum(),\n        axis=0\n    ) * 100\n)\n\nprint(\"Total Subjects:\", len(subject_counts))\n\nprint(\"\\nSubject-wise Positive Event Counts:\")\ndisplay(subject_counts)\n\nprint(\"\\nSubject-wise Positive Event Percentages:\")\ndisplay(subject_percentages.round(3))\n\nplt.figure(figsize=(12, 6))\n\nsns.heatmap(\n    subject_percentages,\n    annot=True,\n    fmt=\".2f\",\n    cmap=\"Purples\"\n)\n\nplt.title(\"Subject-wise Positive Event Distribution (%)\")\nplt.xlabel(\"Movement Events\")\nplt.ylabel(\"Subject\")\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:03:13.558034Z","iopub.execute_input":"2026-10-11T14:03:13.558944Z","iopub.status.idle":"2026-10-11T14:03:13.933654Z","shell.execute_reply.started":"2026-10-11T14:03:13.558914Z","shell.execute_reply":"2026-10-11T14:03:13.932943Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 7 — Subject-wise Event Distribution\n\nHumne subject-wise EDA perform ki taake different participants ke EEG event distributions analyze kar sakein. Hum training aur validation ke liye separate subjects use karenge, jis se data leakage avoid hogi aur model ki generalization properly evaluate hogi.\n","metadata":{}},{"cell_type":"code","source":"\nimport re\nimport pandas as pd\n\nTRAIN_SUBJECTS = list(range(1, 11))\nVAL_SUBJECTS = [11, 12]\n\ndef get_subject(filename):\n    return int(re.search(r\"subj(\\d+)\", filename).group(1))\n\ntrain_event_files = [\n    f for f in event_files\n    if get_subject(f) in TRAIN_SUBJECTS\n]\n\nval_event_files = [\n    f for f in event_files\n    if get_subject(f) in VAL_SUBJECTS\n]\n\nassert set(train_event_files).isdisjoint(val_event_files)\nassert len(train_event_files) + len(val_event_files) == len(event_files)\n\ntrain_rows = event_summary.loc[\n    event_summary[\"File\"].isin(train_event_files),\n    \"Rows\"\n].sum()\n\nval_rows = event_summary.loc[\n    event_summary[\"File\"].isin(val_event_files),\n    \"Rows\"\n].sum()\n\nprint(\"Training Subjects:\", TRAIN_SUBJECTS)\nprint(\"Validation Subjects:\", VAL_SUBJECTS)\n\nprint(\"\\nTraining Files:\", len(train_event_files))\nprint(\"Validation Files:\", len(val_event_files))\n\nprint(\"\\nTraining Time Points:\", f\"{train_rows:,}\")\nprint(\"Validation Time Points:\", f\"{val_rows:,}\")\n\nprint(\"\\nTraining Percentage:\",\n      round(train_rows / (train_rows + val_rows) * 100, 2))\n\nprint(\"Validation Percentage:\",\n      round(val_rows / (train_rows + val_rows) * 100, 2))\n\nprint(\"\\nSubject Leakage:\", bool(\n    set(TRAIN_SUBJECTS) & set(VAL_SUBJECTS)\n))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:03:13.934769Z","iopub.execute_input":"2026-10-11T14:03:13.935093Z","iopub.status.idle":"2026-10-11T14:03:13.947979Z","shell.execute_reply.started":"2026-10-11T14:03:13.935064Z","shell.execute_reply":"2026-10-11T14:03:13.947019Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 8 — Subject-wise Training and Validation Split\n\nHumne subject-wise validation strategy use ki hai. Is mein training aur validation subjects completely separate hain, jis se model ki generalization ability evaluate hoti hai aur subject overlap avoid hota hai.\n","metadata":{}},{"cell_type":"code","source":"\nimport zipfile\nimport numpy as np\nimport pandas as pd\n\nEEG_COLS = [\n    c for c in eeg_sample.columns\n    if c != \"id\"\n]\n\nchannel_sum = np.zeros(32, dtype=np.float64)\nchannel_sq_sum = np.zeros(32, dtype=np.float64)\ntotal_samples = 0\n\nwith zipfile.ZipFile(train_zip) as z:\n    for event_filename in train_event_files:\n\n        data_filename = event_filename.replace(\n            \"_events.csv\", \"_data.csv\"\n        )\n\n        with z.open(data_filename) as f:\n            for chunk in pd.read_csv(\n                f,\n                usecols=EEG_COLS,\n                chunksize=100000\n            ):\n                X = chunk.to_numpy(dtype=np.float64)\n\n                if not np.isfinite(X).all():\n                    raise ValueError(\n                        f\"Invalid EEG values in {data_filename}\"\n                    )\n\n                channel_sum += X.sum(axis=0)\n                channel_sq_sum += np.square(X).sum(axis=0)\n                total_samples += len(X)\n\neeg_mean = channel_sum / total_samples\n\neeg_std = np.sqrt(\n    np.maximum(\n        channel_sq_sum / total_samples - eeg_mean**2,\n        0\n    )\n)\n\neeg_std = np.maximum(eeg_std, 1e-6)\n\nnormalization_df = pd.DataFrame({\n    \"Channel\": EEG_COLS,\n    \"Mean\": eeg_mean,\n    \"Std\": eeg_std\n})\n\nprint(\"Training Samples Used:\", f\"{total_samples:,}\")\nprint(\"Channels:\", len(EEG_COLS))\nprint(\"All Statistics Finite:\",\n      np.isfinite(eeg_mean).all()\n      and np.isfinite(eeg_std).all())\n\nassert total_samples == train_rows\n\ndisplay(normalization_df.round(3))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:03:13.949018Z","iopub.execute_input":"2026-10-11T14:03:13.94962Z","iopub.status.idle":"2026-10-11T14:03:59.387952Z","shell.execute_reply.started":"2026-10-11T14:03:13.949598Z","shell.execute_reply":"2026-10-11T14:03:59.387297Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 9 — EEG Normalization Statistics\n\nHumne training-only Z-score normalization select ki hai. Ismein har EEG value se channel ka training mean subtract karke standard deviation se divide karenge. Isse features comparable scale par aate hain aur data leakage avoid hoti hai.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\n# Apply training statistics to the EDA sample\nX_before = eeg_eda[EEG_COLS].to_numpy(dtype=np.float32)\n\nX_normalized = (\n    X_before - eeg_mean.astype(np.float32)\n) / eeg_std.astype(np.float32)\n\nprint(\"Original Shape:\", X_before.shape)\nprint(\"Normalized Shape:\", X_normalized.shape)\nprint(\"Missing/Infinite Values:\",\n      np.sum(~np.isfinite(X_normalized)))\n\ncomparison_df = pd.DataFrame({\n    \"Channel\": EEG_COLS,\n    \"Original Mean\": X_before.mean(axis=0),\n    \"Normalized Sample Mean\": X_normalized.mean(axis=0),\n    \"Normalized Sample Std\": X_normalized.std(axis=0)\n})\n\ndisplay(comparison_df.round(3))\n\nplt.figure(figsize=(12, 4))\nplt.plot(\n    X_normalized[:1000, EEG_COLS.index(\"Fp1\")],\n    label=\"Fp1\"\n)\nplt.plot(\n    X_normalized[:1000, EEG_COLS.index(\"Cz\")],\n    label=\"Cz\"\n)\n\nplt.title(\"Normalized EEG Signals\")\nplt.xlabel(\"Time Point\")\nplt.ylabel(\"Z-Score\")\nplt.legend()\nplt.grid(alpha=0.2)\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:23:58.789704Z","iopub.execute_input":"2026-10-11T14:23:58.790154Z","iopub.status.idle":"2026-10-11T14:23:59.011926Z","shell.execute_reply.started":"2026-10-11T14:23:58.790126Z","shell.execute_reply":"2026-10-11T14:23:59.011156Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 10 — EEG Normalization Verification\n\nHumne Z-score normalization apply ki, jisme har EEG value se training mean subtract karke training standard deviation se divide kiya. Is se EEG channels ko comparable scale par represent karna possible hota hai.\n\n\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport pandas as pd\nimport zipfile\n\nSEQ_LEN = 128\nTRAIN_STRIDE = 64\n\n# Use first training recording\nsample_event_file = train_event_files[0]\nsample_data_file = sample_event_file.replace(\n    \"_events.csv\", \"_data.csv\"\n)\n\nwith zipfile.ZipFile(train_zip) as z:\n    with z.open(sample_data_file) as f:\n        eeg_df = pd.read_csv(f, nrows=20000)\n\n    with z.open(sample_event_file) as f:\n        labels_df = pd.read_csv(f, nrows=20000)\n\n# Verify alignment\nassert eeg_df[\"id\"].equals(labels_df[\"id\"])\n\n# Normalize EEG\nX = eeg_df[EEG_COLS].to_numpy(dtype=np.float32)\nX = (X - eeg_mean.astype(np.float32)) / eeg_std.astype(np.float32)\n\n# Six event labels\nY = labels_df[EVENT_COLS].to_numpy(dtype=np.float32)\n\n# Generate sequence start indices\nstarts = np.arange(\n    0,\n    len(X) - SEQ_LEN + 1,\n    TRAIN_STRIDE\n)\n\nX_sequences = np.stack([\n    X[s:s + SEQ_LEN] for s in starts\n])\n\nY_sequences = np.stack([\n    Y[s:s + SEQ_LEN] for s in starts\n])\n\nprint(\"Recording:\", sample_data_file)\nprint(\"Original EEG Shape:\", X.shape)\nprint(\"Original Labels Shape:\", Y.shape)\n\nprint(\"\\nTotal Sequences:\", len(starts))\nprint(\"Input Sequences Shape:\", X_sequences.shape)\nprint(\"Output Sequences Shape:\", Y_sequences.shape)\n\nprint(\"\\nFirst Sequence:\")\nprint(\"Start:\", starts[0])\nprint(\"End:\", starts[0] + SEQ_LEN - 1)\n\nprint(\"\\nEEG and Label Alignment:\",\n      X_sequences.shape[:2] == Y_sequences.shape[:2])\n\nassert X_sequences.shape[1:] == (128, 32)\nassert Y_sequences.shape[1:] == (128, 6)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:25:13.338686Z","iopub.execute_input":"2026-10-11T14:25:13.339022Z","iopub.status.idle":"2026-10-11T14:25:13.439927Z","shell.execute_reply.started":"2026-10-11T14:25:13.338996Z","shell.execute_reply":"2026-10-11T14:25:13.439083Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 11 — EEG Sequence Preparation\n\nHumne EEG data ko 128 time-step sequences mein convert kiya. Har time step par 32 EEG features aur six event labels hain. Hum causal RNN/LSTM use karenge taake prediction ke waqt future EEG readings use na hon.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport pandas as pd\n\n# Calculate counts using training subjects only\ntrain_summary = event_summary[\n    event_summary[\"File\"].isin(train_event_files)\n]\n\ntrain_positive = (\n    train_summary[EVENT_COLS]\n    .sum()\n    .to_numpy(dtype=np.float64)\n)\n\ntrain_total = int(train_summary[\"Rows\"].sum())\ntrain_negative = train_total - train_positive\n\n# Raw imbalance ratio\nraw_pos_weights = train_negative / np.maximum(train_positive, 1)\n\n# Conservative weights for stable training\npos_weights = np.clip(\n    np.sqrt(raw_pos_weights),\n    1.0,\n    8.0\n).astype(np.float32)\n\nweight_table = pd.DataFrame({\n    \"Event\": EVENT_COLS,\n    \"Positive\": train_positive.astype(int),\n    \"Negative\": train_negative.astype(int),\n    \"Positive (%)\": train_positive / train_total * 100,\n    \"Raw Weight\": raw_pos_weights,\n    \"Selected Weight\": pos_weights\n})\n\ndisplay(weight_table.round(3))\n\nprint(\"Selected Positive Weights:\", pos_weights)\nprint(\"Training Time Points:\", f\"{train_total:,}\")\n\nassert np.isfinite(pos_weights).all()\nassert (pos_weights >= 1).all()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:26:01.754662Z","iopub.execute_input":"2026-10-11T14:26:01.755322Z","iopub.status.idle":"2026-10-11T14:26:01.773384Z","shell.execute_reply.started":"2026-10-11T14:26:01.755296Z","shell.execute_reply":"2026-10-11T14:26:01.772763Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 12 — Class Imbalance Handling\n\nHumne class imbalance address karne ke liye training-only positive class weights calculate kiye. In weights ko weighted Binary Cross-Entropy loss mein use karenge, taake minority events ko learning ke waqt additional importance mile.\n","metadata":{}},{"cell_type":"code","source":"\nimport zipfile\nimport numpy as np\nimport pandas as pd\n\n# Keep one ZIP handle available for data loading\ntrain_archive = zipfile.ZipFile(train_zip, \"r\")\n\nmean32 = eeg_mean.astype(np.float32)\nstd32 = eeg_std.astype(np.float32)\n\ndef load_eeg_recording(event_filename):\n    data_filename = event_filename.replace(\n        \"_events.csv\", \"_data.csv\"\n    )\n\n    with train_archive.open(data_filename) as f:\n        eeg = pd.read_csv(\n            f,\n            usecols=[\"id\"] + EEG_COLS\n        )\n\n    with train_archive.open(event_filename) as f:\n        events = pd.read_csv(\n            f,\n            usecols=[\"id\"] + EVENT_COLS\n        )\n\n    if not eeg[\"id\"].equals(events[\"id\"]):\n        raise ValueError(\n            f\"EEG-label alignment failed: {event_filename}\"\n        )\n\n    X = eeg[EEG_COLS].to_numpy(dtype=np.float32)\n    Y = events[EVENT_COLS].to_numpy(dtype=np.float32)\n\n    X = (X - mean32) / std32\n\n    if not np.isfinite(X).all():\n        raise ValueError(\n            f\"Invalid normalized values: {event_filename}\"\n        )\n\n    return X, Y\n\n# Test the loader on one recording\ntest_X, test_Y = load_eeg_recording(train_event_files[0])\n\nprint(\"Recording:\", train_event_files[0])\nprint(\"EEG Shape:\", test_X.shape)\nprint(\"Labels Shape:\", test_Y.shape)\nprint(\"EEG dtype:\", test_X.dtype)\nprint(\"Labels dtype:\", test_Y.dtype)\nprint(\"Finite EEG Values:\", np.isfinite(test_X).all())\nprint(\"Labels Unique Values:\", np.unique(test_Y))\n\nassert test_X.shape[1] == 32\nassert test_Y.shape[1] == 6\nassert len(test_X) == len(test_Y)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:26:43.56313Z","iopub.execute_input":"2026-10-11T14:26:43.563397Z","iopub.status.idle":"2026-10-11T14:26:44.66911Z","shell.execute_reply.started":"2026-10-11T14:26:43.563375Z","shell.execute_reply":"2026-10-11T14:26:44.668219Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 13 — EEG Data Loading Pipeline\n\nHumne reusable EEG data loader implement kiya jo input-label alignment verify karta hai aur training-only normalization apply karta hai. Is se preprocessing consistent aur reproducible rehti hai.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport tensorflow as tf\n\nSEQ_LEN = 128\nTRAIN_STRIDE = 64\nBATCH_SIZE = 256\n\ndef sequence_generator(file_list, stride):\n    for filename in file_list:\n        X, Y = load_eeg_recording(filename)\n\n        # Build complete, causal sequences\n        for start in range(0, len(X) - SEQ_LEN + 1, stride):\n            end = start + SEQ_LEN\n\n            yield (\n                X[start:end],\n                Y[start:end]\n            )\n\ndef make_dataset(file_list, stride, training=False):\n    output_signature = (\n        tf.TensorSpec(\n            shape=(SEQ_LEN, 32),\n            dtype=tf.float32\n        ),\n        tf.TensorSpec(\n            shape=(SEQ_LEN, 6),\n            dtype=tf.float32\n        )\n    )\n\n    ds = tf.data.Dataset.from_generator(\n        lambda: sequence_generator(file_list, stride),\n        output_signature=output_signature\n    )\n\n    if training:\n        ds = ds.shuffle(\n            buffer_size=2048,\n            seed=42,\n            reshuffle_each_iteration=True\n        )\n\n    ds = ds.batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)\n\n    return ds\n\ntrain_ds = make_dataset(\n    train_event_files,\n    TRAIN_STRIDE,\n    training=True\n)\n\nval_ds = make_dataset(\n    val_event_files,\n    SEQ_LEN,\n    training=False\n)\n\n# Verify one batch\nfor batch_X, batch_Y in train_ds.take(1):\n    print(\"Training Batch X:\", batch_X.shape)\n    print(\"Training Batch Y:\", batch_Y.shape)\n    print(\"X dtype:\", batch_X.dtype)\n    print(\"Y dtype:\", batch_Y.dtype)\n    print(\"Positive Labels in Batch:\",\n          int(tf.reduce_sum(batch_Y).numpy()))\n\nprint(\"\\nTraining and Validation Datasets Ready!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:27:33.995019Z","iopub.execute_input":"2026-10-11T14:27:33.995453Z","iopub.status.idle":"2026-10-11T14:27:38.165295Z","shell.execute_reply.started":"2026-10-11T14:27:33.99539Z","shell.execute_reply":"2026-10-11T14:27:38.164496Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 14 — Memory-Efficient Sequence Generator\n\nHumne TensorFlow tf.data pipeline implement ki hai jo EEG recordings se sequential windows generate karti hai. Is se training memory-efficient rehti hai aur har EEG time point ka label corresponding signal ke saath aligned rehta hai.\n","metadata":{}},{"cell_type":"code","source":"\nimport tensorflow as tf\nfrom tensorflow.keras import layers, models\n\ntf.keras.utils.set_random_seed(42)\n\ndef build_simple_rnn():\n    model = models.Sequential([\n        layers.Input(shape=(128, 32)),\n\n        layers.SimpleRNN(\n            64,\n            return_sequences=True\n        ),\n\n        layers.Dropout(0.2),\n\n        layers.Dense(\n            6,\n            activation=\"sigmoid\"\n        )\n    ], name=\"M0_Simple_RNN\")\n\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(\n            learning_rate=0.001\n        ),\n        loss=\"binary_crossentropy\"\n    )\n\n    return model\n\nm0 = build_simple_rnn()\n\nm0.summary()\n\n# Verify prediction shape\ndummy_input = tf.zeros((2, 128, 32))\ndummy_output = m0(dummy_input)\n\nprint(\"\\nInput Shape:\", dummy_input.shape)\nprint(\"Output Shape:\", dummy_output.shape)\nprint(\"Total Parameters:\", m0.count_params())\n\nassert dummy_output.shape == (2, 128, 6)\n\nprint(\"\\nM0 Simple RNN Architecture Verified!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:32:03.658634Z","iopub.execute_input":"2026-10-11T14:32:03.659318Z","iopub.status.idle":"2026-10-11T14:32:05.211126Z","shell.execute_reply.started":"2026-10-11T14:32:03.65929Z","shell.execute_reply":"2026-10-11T14:32:05.210408Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 15 — Simple RNN Model Architecture\n\nHumne Simple RNN ko baseline model select kiya kyunki ye sequential EEG data ke temporal patterns learn karta hai. Return sequences True rakha hai taake har EEG time step ke liye six movement events ki probabilities predict ho sakein.\n","metadata":{}},{"cell_type":"code","source":"\nimport os\nimport numpy as np\nimport tensorflow as tf\n\nCACHE_DIR = \"/kaggle/working/eeg_cache\"\nos.makedirs(CACHE_DIR, exist_ok=True)\n\nall_files = train_event_files + val_event_files\n\nfor i, filename in enumerate(all_files, 1):\n    cache_name = os.path.basename(\n        filename.replace(\"_events.csv\", \"\")\n    )\n\n    x_path = os.path.join(CACHE_DIR, cache_name + \"_X.npy\")\n    y_path = os.path.join(CACHE_DIR, cache_name + \"_Y.npy\")\n\n    if not (os.path.exists(x_path) and os.path.exists(y_path)):\n        X, Y = load_eeg_recording(filename)\n\n        np.save(x_path, X)\n        np.save(y_path, Y)\n\n        del X, Y\n\n    if i % 10 == 0 or i == len(all_files):\n        print(f\"Cached {i}/{len(all_files)} recordings\")\n\nprint(\"\\nCaching Complete!\")\n\nprint(\"Total Cached Recordings:\", len(all_files))\nprint(\"Cache Location:\", CACHE_DIR)\n\ncache_size = sum(\n    os.path.getsize(os.path.join(CACHE_DIR, f))\n    for f in os.listdir(CACHE_DIR)\n) / (1024**3)\n\nprint(\"Cache Size (GB):\", round(cache_size, 3))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:34:25.774979Z","iopub.execute_input":"2026-10-11T14:34:25.775507Z","iopub.status.idle":"2026-10-11T14:35:39.624936Z","shell.execute_reply.started":"2026-10-11T14:34:25.77548Z","shell.execute_reply":"2026-10-11T14:35:39.624291Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 16 — Fast EEG Data Caching\n\nHumne preprocessing ke baad EEG data ko reusable NumPy format mein cache kiya, taake training ke multiple epochs mein expensive CSV parsing repeat na karni pade.\n","metadata":{}},{"cell_type":"code","source":"\nimport os\nimport numpy as np\nimport tensorflow as tf\n\nBATCH_SIZE = 256\nSEQ_LEN = 128\nTRAIN_STRIDE = 64\n\ndef cached_sequence_generator(file_list, stride):\n    for filename in file_list:\n        cache_name = os.path.basename(\n            filename.replace(\"_events.csv\", \"\")\n        )\n\n        x_path = os.path.join(\n            CACHE_DIR, cache_name + \"_X.npy\"\n        )\n        y_path = os.path.join(\n            CACHE_DIR, cache_name + \"_Y.npy\"\n        )\n\n        X = np.load(x_path, mmap_mode=\"r\")\n        Y = np.load(y_path, mmap_mode=\"r\")\n\n        for start in range(0, len(X) - SEQ_LEN + 1, stride):\n            end = start + SEQ_LEN\n\n            yield (\n                np.asarray(X[start:end], dtype=np.float32),\n                np.asarray(Y[start:end], dtype=np.float32)\n            )\n\ndef make_cached_dataset(file_list, stride, training=False):\n    output_signature = (\n        tf.TensorSpec(shape=(128, 32), dtype=tf.float32),\n        tf.TensorSpec(shape=(128, 6), dtype=tf.float32)\n    )\n\n    ds = tf.data.Dataset.from_generator(\n        lambda: cached_sequence_generator(file_list, stride),\n        output_signature=output_signature\n    )\n\n    if training:\n        ds = ds.shuffle(\n            buffer_size=2048,\n            seed=42,\n            reshuffle_each_iteration=True\n        )\n\n    ds = ds.batch(BATCH_SIZE)\n    ds = ds.prefetch(tf.data.AUTOTUNE)\n\n    return ds\n\ntrain_ds = make_cached_dataset(\n    train_event_files,\n    TRAIN_STRIDE,\n    training=True\n)\n\nval_ds = make_cached_dataset(\n    val_event_files,\n    SEQ_LEN,\n    training=False\n)\n\n# Calculate number of complete sequences\ndef count_sequences(file_list, stride):\n    total = 0\n\n    for filename in file_list:\n        cache_name = os.path.basename(\n            filename.replace(\"_events.csv\", \"\")\n        )\n\n        path = os.path.join(\n            CACHE_DIR, cache_name + \"_X.npy\"\n        )\n\n        X = np.load(path, mmap_mode=\"r\")\n\n        if len(X) >= SEQ_LEN:\n            total += 1 + (len(X) - SEQ_LEN) // stride\n\n    return total\n\nn_train_seq = count_sequences(\n    train_event_files, TRAIN_STRIDE\n)\n\nn_val_seq = count_sequences(\n    val_event_files, SEQ_LEN\n)\n\nprint(\"Training Sequences:\", f\"{n_train_seq:,}\")\nprint(\"Validation Sequences:\", f\"{n_val_seq:,}\")\nprint(\"Training Batches:\", (n_train_seq + BATCH_SIZE - 1) // BATCH_SIZE)\nprint(\"Validation Batches:\", (n_val_seq + BATCH_SIZE - 1) // BATCH_SIZE)\n\nfor X_batch, Y_batch in train_ds.take(1):\n    print(\"\\nX Batch Shape:\", X_batch.shape)\n    print(\"Y Batch Shape:\", Y_batch.shape)\n\nprint(\"\\nCached TensorFlow Pipeline Ready!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:36:22.752736Z","iopub.execute_input":"2026-10-11T14:36:22.753493Z","iopub.status.idle":"2026-10-11T14:36:23.508644Z","shell.execute_reply.started":"2026-10-11T14:36:22.753455Z","shell.execute_reply":"2026-10-11T14:36:23.507961Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 17 — Cached TensorFlow Data Pipeline\n\nHumne memory-mapped NumPy arrays aur TensorFlow tf.data pipeline use ki, taake large EEG dataset ko efficiently train kiya ja sake. Training aur validation subjects separate rakhe hain, jisse subject leakage avoid hoti hai.\n","metadata":{}},{"cell_type":"code","source":"\nimport os\nimport time\nimport tensorflow as tf\n\nMODEL_DIR = \"/kaggle/working/saved_models\"\nos.makedirs(MODEL_DIR, exist_ok=True)\n\nm0_path = os.path.join(MODEL_DIR, \"M0_Simple_RNN.keras\")\n\nm0_callbacks = [\n    tf.keras.callbacks.EarlyStopping(\n        monitor=\"val_loss\",\n        patience=3,\n        restore_best_weights=True,\n        verbose=1\n    ),\n\n    tf.keras.callbacks.ModelCheckpoint(\n        filepath=m0_path,\n        monitor=\"val_loss\",\n        save_best_only=True,\n        verbose=1\n    ),\n\n    tf.keras.callbacks.ReduceLROnPlateau(\n        monitor=\"val_loss\",\n        factor=0.5,\n        patience=2,\n        min_lr=1e-5,\n        verbose=1\n    )\n]\n\nprint(\"Starting M0 Simple RNN Training...\")\nprint(\"Maximum Epochs: 8\")\nprint(\"Training Batches:\", 907)\nprint(\"Validation Batches:\", 96)\n\nstart_time = time.time()\n\nhistory_m0 = m0.fit(\n    train_ds,\n    validation_data=val_ds,\n    epochs=8,\n    callbacks=m0_callbacks,\n    verbose=1\n)\n\nm0_training_time = time.time() - start_time\n\nprint(\"\\nM0 Training Complete!\")\nprint(\"Epochs Completed:\", len(history_m0.history[\"loss\"]))\nprint(\"Training Time (minutes):\",\n      round(m0_training_time / 60, 2))\nprint(\"Best Validation Loss:\",\n      round(min(history_m0.history[\"val_loss\"]), 6))\nprint(\"Model Saved At:\", m0_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T14:42:44.425675Z","iopub.execute_input":"2026-10-11T14:42:44.426253Z","iopub.status.idle":"2026-10-11T14:52:18.188351Z","shell.execute_reply.started":"2026-10-11T14:42:44.426224Z","shell.execute_reply":"2026-10-11T14:52:18.187598Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 18 — Simple RNN Model Training\n\n- Maximum epochs: 8\n- Optimizer: Adam\n- Loss: Binary Cross-Entropy\n- Early Stopping: Patience 3\n- Best Model Checkpoint: Enabled\n- Learning Rate Reduction: Enabled\n\n\nHumne Simple RNN ko baseline model ke taur par train kiya. Early Stopping overfitting ko limit karne ke liye use ki aur ModelCheckpoint se best validation performance wala model save kiya.\n","metadata":{}},{"cell_type":"code","source":"\nimport matplotlib.pyplot as plt\nimport numpy as np\n\ntrain_loss = history_m0.history[\"loss\"]\nval_loss = history_m0.history[\"val_loss\"]\n\nepochs = np.arange(1, len(train_loss) + 1)\nbest_epoch = int(np.argmin(val_loss)) + 1\n\nplt.figure(figsize=(10, 5))\n\nplt.plot(\n    epochs,\n    train_loss,\n    marker=\"o\",\n    linewidth=2,\n    label=\"Training Loss\"\n)\n\nplt.plot(\n    epochs,\n    val_loss,\n    marker=\"s\",\n    linewidth=2,\n    label=\"Validation Loss\"\n)\n\nplt.axvline(\n    best_epoch,\n    color=\"green\",\n    linestyle=\"--\",\n    label=f\"Best Epoch: {best_epoch}\"\n)\n\nplt.title(\"M0 Simple RNN - Training vs Validation Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Binary Cross-Entropy Loss\")\nplt.xticks(epochs)\nplt.legend()\nplt.grid(alpha=0.3)\nplt.tight_layout()\n\nplt.savefig(\n    \"/kaggle/working/M0_Loss_Curve.png\",\n    dpi=200,\n    bbox_inches=\"tight\"\n)\n\nplt.show()\n\nprint(\"Best Epoch:\", best_epoch)\nprint(\"Best Validation Loss:\", round(min(val_loss), 6))\nprint(\"Final Training Loss:\", round(train_loss[-1], 6))\nprint(\"Final Validation Loss:\", round(val_loss[-1], 6))\nprint(\"Plot Saved Successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T15:07:19.703339Z","iopub.execute_input":"2026-10-11T15:07:19.703897Z","iopub.status.idle":"2026-10-11T15:07:20.177869Z","shell.execute_reply.started":"2026-10-11T15:07:19.70387Z","shell.execute_reply":"2026-10-11T15:07:20.177207Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 19 — Training and Validation Loss Visualization\n\nHumne learning curves analyze kiye. Validation loss epoch 6 par minimum 0.129761 tha. Uske baad validation loss mein slight increase aaya, isliye best epoch ke weights restore kiye gaye.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport pandas as pd\nfrom sklearn.metrics import (\n    accuracy_score,\n    balanced_accuracy_score,\n    precision_score,\n    recall_score,\n    f1_score,\n    roc_auc_score\n)\n\n# Generate predictions for validation sequences\nprint(\"Generating M0 validation predictions...\")\n\ny_true_batches = []\ny_prob_batches = []\n\nfor batch_X, batch_Y in val_ds:\n    batch_prob = m0(batch_X, training=False).numpy()\n\n    y_true_batches.append(\n        batch_Y.numpy().reshape(-1, 6)\n    )\n    y_prob_batches.append(\n        batch_prob.reshape(-1, 6)\n    )\n\ny_true_m0 = np.concatenate(y_true_batches, axis=0)\ny_prob_m0 = np.concatenate(y_prob_batches, axis=0)\n\n# Default classification threshold\nTHRESHOLD = 0.5\ny_pred_m0 = (y_prob_m0 >= THRESHOLD).astype(int)\n\nresults_m0 = []\n\nfor i, event in enumerate(EVENT_COLS):\n    true = y_true_m0[:, i].astype(int)\n    pred = y_pred_m0[:, i]\n    prob = y_prob_m0[:, i]\n\n    results_m0.append({\n        \"Event\": event,\n        \"Accuracy\": accuracy_score(true, pred),\n        \"Balanced Accuracy\": balanced_accuracy_score(true, pred),\n        \"Precision\": precision_score(\n            true, pred, zero_division=0\n        ),\n        \"Recall\": recall_score(\n            true, pred, zero_division=0\n        ),\n        \"F1\": f1_score(\n            true, pred, zero_division=0\n        ),\n        \"ROC AUC\": roc_auc_score(true, prob)\n    })\n\nmetrics_m0 = pd.DataFrame(results_m0)\n\nprint(\"\\nM0 Simple RNN — Validation Metrics\")\ndisplay(metrics_m0.round(4))\n\nprint(\"\\nMacro Average Metrics:\")\ndisplay(\n    metrics_m0.drop(columns=[\"Event\"])\n    .mean()\n    .to_frame(name=\"M0 Score\")\n    .round(4)\n)\n\nprint(\"\\nEvaluated Time Points:\", f\"{len(y_true_m0):,}\")\nprint(\"Prediction Shape:\", y_prob_m0.shape)\n\nmetrics_m0.to_csv(\n    \"/kaggle/working/M0_Validation_Metrics.csv\",\n    index=False\n)\n\nprint(\"\\nMetrics Saved Successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T15:10:01.443182Z","iopub.execute_input":"2026-10-11T15:10:01.443613Z","iopub.status.idle":"2026-10-11T15:10:51.884857Z","shell.execute_reply.started":"2026-10-11T15:10:01.443586Z","shell.execute_reply":"2026-10-11T15:10:51.884153Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 20 — Simple RNN Validation Evaluation\nHumne unseen validation subjects par model evaluate kiya. ROC AUC model ki positive aur negative events ko rank karne ki ability measure karta hai, jabke Precision, Recall aur F1 selected classification threshold par detection performance show karte hain.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport pandas as pd\nfrom sklearn.metrics import (\n    precision_score,\n    recall_score,\n    f1_score\n)\n\nthresholds = np.arange(0.02, 0.51, 0.02)\n\nthreshold_results = []\n\nfor threshold in thresholds:\n    predictions = (\n        y_prob_m0 >= threshold\n    ).astype(np.uint8)\n\n    threshold_results.append({\n        \"Threshold\": round(float(threshold), 2),\n        \"Precision\": precision_score(\n            y_true_m0,\n            predictions,\n            average=\"macro\",\n            zero_division=0\n        ),\n        \"Recall\": recall_score(\n            y_true_m0,\n            predictions,\n            average=\"macro\",\n            zero_division=0\n        ),\n        \"F1\": f1_score(\n            y_true_m0,\n            predictions,\n            average=\"macro\",\n            zero_division=0\n        )\n    })\n\nthreshold_df = pd.DataFrame(threshold_results)\n\nbest_index = threshold_df[\"F1\"].idxmax()\nbest_threshold_m0 = float(\n    threshold_df.loc[best_index, \"Threshold\"]\n)\n\nprint(\"M0 Threshold Optimization Results:\")\ndisplay(threshold_df.round(4))\n\nprint(\"\\nBest Threshold:\", best_threshold_m0)\nprint(\n    \"Best Macro F1:\",\n    round(float(threshold_df.loc[best_index, \"F1\"]), 4)\n)\nprint(\n    \"Recall at Best Threshold:\",\n    round(float(threshold_df.loc[best_index, \"Recall\"]), 4)\n)\n\nthreshold_df.to_csv(\n    \"/kaggle/working/M0_Threshold_Results.csv\",\n    index=False\n)\n\nprint(\"\\nThreshold Results Saved!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T15:20:09.110832Z","iopub.execute_input":"2026-10-11T15:20:09.111131Z","iopub.status.idle":"2026-10-11T15:22:01.540407Z","shell.execute_reply.started":"2026-10-11T15:20:09.111109Z","shell.execute_reply":"2026-10-11T15:22:01.539512Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 21 — Classification Threshold Optimization\n\nHumne validation dataset par classification threshold tune kiya, kyunki imbalanced datasets mein default 0.5 threshold optimal nahi hota. Threshold tuning se Precision aur Recall ke beech trade-off control hota hai. ROC AUC threshold-independent hota hai, isliye threshold change karne se AUC improve nahi hota.\n","metadata":{}},{"cell_type":"code","source":"\nimport tensorflow as tf\nfrom tensorflow.keras import layers, models\n\ntf.keras.utils.set_random_seed(42)\n\n# Positive class weights from Cell 12\npositive_weights = tf.constant(\n    pos_weights,\n    dtype=tf.float32\n)\n\ndef weighted_binary_crossentropy(y_true, y_pred):\n    y_true = tf.cast(y_true, tf.float32)\n\n    # Avoid log(0)\n    eps = tf.keras.backend.epsilon()\n    y_pred = tf.clip_by_value(\n        y_pred,\n        eps,\n        1.0 - eps\n    )\n\n    # Weighted positive and standard negative loss\n    loss = -(\n        positive_weights * y_true * tf.math.log(y_pred)\n        +\n        (1.0 - y_true) * tf.math.log(1.0 - y_pred)\n    )\n\n    return tf.reduce_mean(loss, axis=-1)\n\ndef build_m1_lstm():\n    model = models.Sequential([\n        layers.Input(shape=(SEQ_LEN, 32)),\n\n        layers.LSTM(\n            64,\n            return_sequences=True\n        ),\n\n        layers.Dropout(0.2),\n\n        layers.Dense(\n            6,\n            activation=\"sigmoid\"\n        )\n    ], name=\"M1_Weighted_LSTM\")\n\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(\n            learning_rate=0.001\n        ),\n        loss=weighted_binary_crossentropy\n    )\n\n    return model\n\nm1 = build_m1_lstm()\n\nm1.summary()\n\n# Verify model output\ndummy_X = tf.zeros((2, SEQ_LEN, 32))\ndummy_Y = m1(dummy_X)\n\nprint(\"\\nInput Shape:\", dummy_X.shape)\nprint(\"Output Shape:\", dummy_Y.shape)\nprint(\"Total Parameters:\", m1.count_params())\nprint(\"Positive Weights:\", pos_weights)\n\nassert dummy_Y.shape == (2, SEQ_LEN, 6)\n\nprint(\"\\nM1 Weighted LSTM Architecture Verified!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T15:26:52.583829Z","iopub.execute_input":"2026-10-11T15:26:52.584547Z","iopub.status.idle":"2026-10-11T15:26:52.858311Z","shell.execute_reply.started":"2026-10-11T15:26:52.584518Z","shell.execute_reply":"2026-10-11T15:26:52.857564Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 22 — Weighted LSTM Architecture\n\nHumne unidirectional LSTM architecture use ki taake future EEG samples ka leakage na ho. Weighted BCE loss minority movement events ko higher penalty deta hai. Is model ki performance Simple RNN baseline ke against compare karenge.\n","metadata":{}},{"cell_type":"code","source":"\nimport os\nimport time\nimport tensorflow as tf\n\n# Set exact dataset cardinality to avoid Unknown steps\ntrain_batches = (n_train_seq + BATCH_SIZE - 1) // BATCH_SIZE\nval_batches = (n_val_seq + BATCH_SIZE - 1) // BATCH_SIZE\n\ntrain_ds_m1 = train_ds.apply(\n    tf.data.experimental.assert_cardinality(train_batches)\n)\n\nval_ds_m1 = val_ds.apply(\n    tf.data.experimental.assert_cardinality(val_batches)\n)\n\nm1_path = os.path.join(\n    MODEL_DIR,\n    \"M1_Weighted_LSTM.keras\"\n)\n\nm1_callbacks = [\n    tf.keras.callbacks.EarlyStopping(\n        monitor=\"val_loss\",\n        patience=3,\n        restore_best_weights=True,\n        verbose=1\n    ),\n\n    tf.keras.callbacks.ModelCheckpoint(\n        filepath=m1_path,\n        monitor=\"val_loss\",\n        save_best_only=True,\n        verbose=1\n    ),\n\n    tf.keras.callbacks.ReduceLROnPlateau(\n        monitor=\"val_loss\",\n        factor=0.5,\n        patience=2,\n        min_lr=1e-5,\n        verbose=1\n    )\n]\n\nprint(\"Starting M1 Weighted LSTM Training...\")\nprint(\"Maximum Epochs: 12\")\nprint(\"Training Batches:\", train_batches)\nprint(\"Validation Batches:\", val_batches)\n\nstart_time = time.time()\n\nhistory_m1 = m1.fit(\n    train_ds_m1,\n    validation_data=val_ds_m1,\n    epochs=12,\n    callbacks=m1_callbacks,\n    verbose=1\n)\n\nm1_training_time = time.time() - start_time\n\nprint(\"\\nM1 Training Complete!\")\nprint(\"Epochs Completed:\", len(history_m1.history[\"loss\"]))\nprint(\n    \"Training Time (minutes):\",\n    round(m1_training_time / 60, 2)\n)\nprint(\n    \"Best Validation Loss:\",\n    round(min(history_m1.history[\"val_loss\"]), 6)\n)\nprint(\"Model Saved At:\", m1_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T15:28:48.699216Z","iopub.execute_input":"2026-10-11T15:28:48.699663Z","iopub.status.idle":"2026-10-11T15:39:34.338172Z","shell.execute_reply.started":"2026-10-11T15:28:48.699632Z","shell.execute_reply":"2026-10-11T15:39:34.337511Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 23 — Weighted LSTM Model Training\n\nHumne class imbalance handle karne ke liye weighted BCE loss ke saath LSTM train kiya. Subject-wise validation aur Early Stopping use ki taake model ki generalization performance evaluate ho sake.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ntrain_loss_m1 = history_m1.history[\"loss\"]\nval_loss_m1 = history_m1.history[\"val_loss\"]\n\nepochs_m1 = np.arange(1, len(train_loss_m1) + 1)\nbest_epoch_m1 = int(np.argmin(val_loss_m1)) + 1\n\nplt.figure(figsize=(10, 5))\n\nplt.plot(\n    epochs_m1,\n    train_loss_m1,\n    marker=\"o\",\n    linewidth=2,\n    label=\"Training Loss\"\n)\n\nplt.plot(\n    epochs_m1,\n    val_loss_m1,\n    marker=\"s\",\n    linewidth=2,\n    label=\"Validation Loss\"\n)\n\nplt.axvline(\n    best_epoch_m1,\n    color=\"green\",\n    linestyle=\"--\",\n    label=f\"Best Epoch: {best_epoch_m1}\"\n)\n\nplt.title(\"M1 Weighted LSTM - Training vs Validation Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Weighted Binary Cross-Entropy Loss\")\nplt.xticks(epochs_m1)\nplt.legend()\nplt.grid(alpha=0.3)\nplt.tight_layout()\n\nplt.savefig(\n    \"/kaggle/working/M1_Loss_Curve.png\",\n    dpi=200,\n    bbox_inches=\"tight\"\n)\n\nplt.show()\n\nprint(\"Best Epoch:\", best_epoch_m1)\nprint(\"Best Validation Loss:\", round(min(val_loss_m1), 6))\nprint(\"Final Training Loss:\", round(train_loss_m1[-1], 6))\nprint(\"Final Validation Loss:\", round(val_loss_m1[-1], 6))\nprint(\"Plot Saved Successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T15:46:40.370319Z","iopub.execute_input":"2026-10-11T15:46:40.371077Z","iopub.status.idle":"2026-10-11T15:46:40.858835Z","shell.execute_reply.started":"2026-10-11T15:46:40.371048Z","shell.execute_reply":"2026-10-11T15:46:40.85793Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 24 — Weighted LSTM Training Visualization\n\nHumne M1 LSTM ki learning curves analyze ki. Validation loss epoch 6 par minimum 0.474663 tha. Early Stopping ne epoch 9 par training stop ki aur best epoch ke weights restore kar diye.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport pandas as pd\n\nfrom sklearn.metrics import (\n    accuracy_score,\n    balanced_accuracy_score,\n    precision_score,\n    recall_score,\n    f1_score,\n    roc_auc_score\n)\n\nprint(\"Generating M1 validation predictions...\")\n\ny_true_batches_m1 = []\ny_prob_batches_m1 = []\n\nfor batch_X, batch_Y in val_ds_m1:\n    probabilities = m1(batch_X, training=False).numpy()\n\n    y_true_batches_m1.append(\n        batch_Y.numpy().reshape(-1, 6)\n    )\n\n    y_prob_batches_m1.append(\n        probabilities.reshape(-1, 6)\n    )\n\ny_true_m1 = np.concatenate(\n    y_true_batches_m1, axis=0\n)\n\ny_prob_m1 = np.concatenate(\n    y_prob_batches_m1, axis=0\n)\n\n# Verify both models were evaluated on identical labels\nassert y_true_m1.shape == y_true_m0.shape\nassert np.array_equal(y_true_m1, y_true_m0)\n\nTHRESHOLD = 0.5\n\ny_pred_m1 = (\n    y_prob_m1 >= THRESHOLD\n).astype(np.uint8)\n\nresults_m1 = []\n\nfor i, event in enumerate(EVENT_COLS):\n    true = y_true_m1[:, i].astype(int)\n    pred = y_pred_m1[:, i]\n    prob = y_prob_m1[:, i]\n\n    results_m1.append({\n        \"Event\": event,\n        \"Accuracy\": accuracy_score(true, pred),\n        \"Balanced Accuracy\": balanced_accuracy_score(true, pred),\n        \"Precision\": precision_score(\n            true, pred, zero_division=0\n        ),\n        \"Recall\": recall_score(\n            true, pred, zero_division=0\n        ),\n        \"F1\": f1_score(\n            true, pred, zero_division=0\n        ),\n        \"ROC AUC\": roc_auc_score(true, prob)\n    })\n\nmetrics_m1 = pd.DataFrame(results_m1)\n\nprint(\"\\nM1 Weighted LSTM — Validation Metrics\")\ndisplay(metrics_m1.round(4))\n\n# Compare macro-average metrics\nm0_macro = metrics_m0.drop(\n    columns=[\"Event\"]\n).mean()\n\nm1_macro = metrics_m1.drop(\n    columns=[\"Event\"]\n).mean()\n\ncomparison_m0_m1 = pd.DataFrame({\n    \"M0 Simple RNN\": m0_macro,\n    \"M1 Weighted LSTM\": m1_macro\n})\n\ncomparison_m0_m1[\"Difference (M1 - M0)\"] = (\n    comparison_m0_m1[\"M1 Weighted LSTM\"]\n    - comparison_m0_m1[\"M0 Simple RNN\"]\n)\n\nprint(\"\\nM0 vs M1 — Macro Average Comparison\")\ndisplay(comparison_m0_m1.round(4))\n\nprint(\"\\nEvaluated Time Points:\", f\"{len(y_true_m1):,}\")\nprint(\"Prediction Shape:\", y_prob_m1.shape)\n\nmetrics_m1.to_csv(\n    \"/kaggle/working/M1_Validation_Metrics.csv\",\n    index=False\n)\n\ncomparison_m0_m1.to_csv(\n    \"/kaggle/working/M0_vs_M1_Comparison.csv\"\n)\n\nprint(\"\\nEvaluation and Comparison Saved Successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T15:47:55.467051Z","iopub.execute_input":"2026-10-11T15:47:55.467745Z","iopub.status.idle":"2026-10-11T15:48:13.322027Z","shell.execute_reply.started":"2026-10-11T15:47:55.467716Z","shell.execute_reply":"2026-10-11T15:48:13.321363Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 25 — M1 LSTM Evaluation and Baseline Comparison\n\nHumne Simple RNN aur Weighted LSTM ko same unseen validation subjects par evaluate kiya. Dono models ki performance threshold-dependent metrics aur ROC AUC se compare ki, taake class imbalance ke bawajood meaningful results mil sakein.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport pandas as pd\nfrom sklearn.metrics import (\n    precision_score,\n    recall_score,\n    f1_score\n)\n\nthresholds = np.arange(0.02, 0.81, 0.02)\n\nthreshold_results_m1 = []\n\nfor threshold in thresholds:\n    predictions = (\n        y_prob_m1 >= threshold\n    ).astype(np.uint8)\n\n    threshold_results_m1.append({\n        \"Threshold\": round(float(threshold), 2),\n        \"Precision\": precision_score(\n            y_true_m1,\n            predictions,\n            average=\"macro\",\n            zero_division=0\n        ),\n        \"Recall\": recall_score(\n            y_true_m1,\n            predictions,\n            average=\"macro\",\n            zero_division=0\n        ),\n        \"F1\": f1_score(\n            y_true_m1,\n            predictions,\n            average=\"macro\",\n            zero_division=0\n        )\n    })\n\nthreshold_df_m1 = pd.DataFrame(threshold_results_m1)\n\nbest_index_m1 = threshold_df_m1[\"F1\"].idxmax()\n\nbest_threshold_m1 = float(\n    threshold_df_m1.loc[best_index_m1, \"Threshold\"]\n)\n\nbest_f1_m1 = float(\n    threshold_df_m1.loc[best_index_m1, \"F1\"]\n)\n\nprint(\"M1 Threshold Optimization Results:\")\ndisplay(threshold_df_m1.round(4))\n\nprint(\"\\nBest M1 Threshold:\", best_threshold_m1)\nprint(\"Best M1 Macro F1:\", round(best_f1_m1, 4))\n\nprint(\"\\nComparison with M0:\")\nprint(\"M0 Best Threshold:\", best_threshold_m0)\nprint(\"M0 Best Macro F1: 0.0701\")\nprint(\"M1 Best Threshold:\", best_threshold_m1)\nprint(\"M1 Best Macro F1:\", round(best_f1_m1, 4))\n\nthreshold_df_m1.to_csv(\n    \"/kaggle/working/M1_Threshold_Results.csv\",\n    index=False\n)\n\nprint(\"\\nThreshold Optimization Saved!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T15:51:06.561863Z","iopub.execute_input":"2026-10-11T15:51:06.562305Z","iopub.status.idle":"2026-10-11T15:54:25.177319Z","shell.execute_reply.started":"2026-10-11T15:51:06.562277Z","shell.execute_reply":"2026-10-11T15:54:25.176742Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 26 — M1 Classification Threshold Optimization\n\nHumne class imbalance ki wajah se classification threshold optimize kiya. Is se Precision aur Recall ka balance improve ho sakta hai. ROC AUC threshold-independent hota hai, isliye threshold tuning usay change nahi karti.\n","metadata":{}},{"cell_type":"code","source":"\nimport tensorflow as tf\nfrom tensorflow.keras import layers, models\n\ntf.keras.utils.set_random_seed(42)\n\ndef build_m2_stacked_lstm():\n    model = models.Sequential([\n        layers.Input(shape=(SEQ_LEN, 32)),\n\n        layers.LSTM(\n            64,\n            return_sequences=True\n        ),\n\n        layers.LayerNormalization(),\n\n        layers.Dropout(0.2),\n\n        layers.LSTM(\n            32,\n            return_sequences=True\n        ),\n\n        layers.LayerNormalization(),\n\n        layers.Dropout(0.2),\n\n        layers.Dense(\n            6,\n            activation=\"sigmoid\"\n        )\n    ], name=\"M2_Stacked_LSTM\")\n\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(\n            learning_rate=0.0005,\n            clipnorm=1.0\n        ),\n        loss=weighted_binary_crossentropy\n    )\n\n    return model\n\nm2 = build_m2_stacked_lstm()\n\nm2.summary()\n\n# Verify input-output alignment\ndummy_X = tf.zeros((2, SEQ_LEN, 32))\ndummy_Y = m2(dummy_X)\n\nprint(\"\\nInput Shape:\", dummy_X.shape)\nprint(\"Output Shape:\", dummy_Y.shape)\nprint(\"Total Parameters:\", m2.count_params())\nprint(\"Positive Class Weights:\", pos_weights)\n\nassert dummy_Y.shape == (2, SEQ_LEN, 6)\n\nprint(\"\\nM2 Stacked LSTM Architecture Verified!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T16:05:26.335008Z","iopub.execute_input":"2026-10-11T16:05:26.335587Z","iopub.status.idle":"2026-10-11T16:05:27.025061Z","shell.execute_reply.started":"2026-10-11T16:05:26.335557Z","shell.execute_reply":"2026-10-11T16:05:27.024368Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 27 — Stacked LSTM Model Architecture\n\nHumne deeper unidirectional LSTM architecture implement kiya jo sequential EEG features ko multiple recurrent layers mein process karta hai. Weighted BCE class imbalance handle karta hai, jabke normalization aur dropout training stability aur regularization ke liye use kiye gaye.\n","metadata":{}},{"cell_type":"code","source":"\nimport os\nimport time\nimport tensorflow as tf\n\nm2_path = os.path.join(\n    MODEL_DIR,\n    \"M2_Stacked_LSTM.keras\"\n)\n\nm2_callbacks = [\n    tf.keras.callbacks.EarlyStopping(\n        monitor=\"val_loss\",\n        patience=3,\n        restore_best_weights=True,\n        verbose=1\n    ),\n\n    tf.keras.callbacks.ModelCheckpoint(\n        filepath=m2_path,\n        monitor=\"val_loss\",\n        save_best_only=True,\n        verbose=1\n    ),\n\n    tf.keras.callbacks.ReduceLROnPlateau(\n        monitor=\"val_loss\",\n        factor=0.5,\n        patience=2,\n        min_lr=1e-5,\n        verbose=1\n    )\n]\n\nprint(\"Starting M2 Stacked LSTM Training...\")\nprint(\"Maximum Epochs: 15\")\nprint(\"Training Batches:\", train_batches)\nprint(\"Validation Batches:\", val_batches)\n\nstart_time = time.time()\n\nhistory_m2 = m2.fit(\n    train_ds_m1,\n    validation_data=val_ds_m1,\n    epochs=15,\n    callbacks=m2_callbacks,\n    verbose=1\n)\n\nm2_training_time = time.time() - start_time\n\nprint(\"\\nM2 Training Complete!\")\nprint(\n    \"Epochs Completed:\",\n    len(history_m2.history[\"loss\"])\n)\nprint(\n    \"Training Time (minutes):\",\n    round(m2_training_time / 60, 2)\n)\nprint(\n    \"Best Epoch:\",\n    int(\n        tf.argmin(\n            history_m2.history[\"val_loss\"]\n        ).numpy()\n    ) + 1\n)\nprint(\n    \"Best Validation Loss:\",\n    round(min(history_m2.history[\"val_loss\"]), 6)\n)\nprint(\"Model Saved At:\", m2_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T16:28:19.400579Z","iopub.execute_input":"2026-10-11T16:28:19.401366Z","iopub.status.idle":"2026-10-11T16:37:27.840387Z","shell.execute_reply.started":"2026-10-11T16:28:19.401329Z","shell.execute_reply":"2026-10-11T16:37:27.839612Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 28 — Stacked LSTM Model Training\n\n\n- Maximum epochs: 15\n- Batch size: 256\n- Optimizer: Adam\n- Learning rate: 0.0005\n- Loss: Weighted Binary Cross-Entropy\n- Early Stopping: Patience 3\n- Model Checkpoint: Enabled\n\nHumne deeper Stacked LSTM model train kiya aur unseen subjects par validation loss monitor ki. Early Stopping aur learning-rate reduction use ki taake unnecessary training aur overfitting ko limit kiya ja sake.\n","metadata":{}},{"cell_type":"code","source":"\nimport matplotlib.pyplot as plt\nimport numpy as np\n\ntrain_loss_m2 = history_m2.history[\"loss\"]\nval_loss_m2 = history_m2.history[\"val_loss\"]\n\nepochs_m2 = np.arange(1, len(train_loss_m2) + 1)\n\nbest_epoch_m2 = int(np.argmin(val_loss_m2)) + 1\nbest_val_loss_m2 = float(np.min(val_loss_m2))\n\nplt.figure(figsize=(10, 5))\n\nplt.plot(\n    epochs_m2,\n    train_loss_m2,\n    marker=\"o\",\n    linewidth=2,\n    label=\"Training Loss\"\n)\n\nplt.plot(\n    epochs_m2,\n    val_loss_m2,\n    marker=\"s\",\n    linewidth=2,\n    label=\"Validation Loss\"\n)\n\nplt.axvline(\n    best_epoch_m2,\n    color=\"gray\",\n    linestyle=\"--\",\n    label=f\"Best Epoch: {best_epoch_m2}\"\n)\n\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Weighted Binary Cross-Entropy Loss\")\nplt.title(\"M2 Stacked LSTM — Training vs Validation Loss\")\nplt.xticks(epochs_m2)\nplt.legend()\nplt.grid(alpha=0.3)\nplt.tight_layout()\n\nplt.savefig(\n    \"/kaggle/working/M2_Loss_Curve.png\",\n    dpi=300,\n    bbox_inches=\"tight\"\n)\n\nplt.show()\n\nprint(\"Best Epoch:\", best_epoch_m2)\nprint(\"Best Validation Loss:\", round(best_val_loss_m2, 6))\nprint(\"Final Training Loss:\", round(train_loss_m2[-1], 6))\nprint(\"Final Validation Loss:\", round(val_loss_m2[-1], 6))\nprint(\"Plot Saved Successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T16:55:24.429006Z","iopub.execute_input":"2026-10-11T16:55:24.429578Z","iopub.status.idle":"2026-10-11T16:55:25.093444Z","shell.execute_reply.started":"2026-10-11T16:55:24.429547Z","shell.execute_reply":"2026-10-11T16:55:25.092633Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 29 — M2 Training and Validation Loss Visualization\n\nM2 model ki validation loss epoch 4 par minimum thi. Uske baad training loss decrease hoti rahi lekin validation loss increase hui, jo overfitting ka indication hai. Early Stopping ne training stop karke best epoch ke weights restore kar diye.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport pandas as pd\n\nfrom sklearn.metrics import (\n    accuracy_score,\n    balanced_accuracy_score,\n    precision_score,\n    recall_score,\n    f1_score,\n    roc_auc_score\n)\n\n# Step 1: Generate M2 predictions\nprint(\"Generating M2 Validation Predictions...\")\n\ny_true_batches_m2 = []\ny_prob_batches_m2 = []\n\nfor X_batch, y_batch in val_ds_m1:\n    probabilities = m2(X_batch, training=False)\n\n    y_true_batches_m2.append(\n        y_batch.numpy().astype(np.uint8)\n    )\n\n    y_prob_batches_m2.append(\n        probabilities.numpy().astype(np.float32)\n    )\n\n# Step 2: Combine all batches\ny_true_m2 = np.concatenate(\n    y_true_batches_m2, axis=0\n).reshape(-1, 6)\n\ny_prob_m2 = np.concatenate(\n    y_prob_batches_m2, axis=0\n).reshape(-1, 6)\n\ndel y_true_batches_m2, y_prob_batches_m2\n\n# Step 3: Verify alignment\nassert y_true_m2.shape == y_prob_m2.shape\nassert np.array_equal(y_true_m2, y_true_m1)\n\nprint(\"Prediction Shape:\", y_prob_m2.shape)\nprint(\"Alignment Verified!\")\n\n# Step 4: Default threshold = 0.5\ny_pred_m2 = (\n    y_prob_m2 >= 0.5\n).astype(np.uint8)\n\n# Step 5: Calculate event-wise metrics\nm2_results = []\n\nfor i, event in enumerate(EVENT_COLS):\n    yt = y_true_m2[:, i]\n    yp = y_pred_m2[:, i]\n    prob = y_prob_m2[:, i]\n\n    m2_results.append({\n        \"Event\": event,\n        \"Accuracy\": accuracy_score(yt, yp),\n        \"Balanced Accuracy\": balanced_accuracy_score(yt, yp),\n        \"Precision\": precision_score(\n            yt, yp, zero_division=0\n        ),\n        \"Recall\": recall_score(\n            yt, yp, zero_division=0\n        ),\n        \"F1\": f1_score(\n            yt, yp, zero_division=0\n        ),\n        \"ROC AUC\": roc_auc_score(yt, prob)\n    })\n\nmetrics_m2 = pd.DataFrame(m2_results)\n\nprint(\"\\nM2 Stacked LSTM — Event-wise Metrics:\")\ndisplay(metrics_m2.round(4))\n\n# Step 6: Macro comparison of all 3 models\nmetric_cols = [\n    \"Accuracy\",\n    \"Balanced Accuracy\",\n    \"Precision\",\n    \"Recall\",\n    \"F1\",\n    \"ROC AUC\"\n]\n\ncomparison_all = pd.DataFrame({\n    \"M0 Simple RNN\": metrics_m0[metric_cols].mean(),\n    \"M1 Weighted LSTM\": metrics_m1[metric_cols].mean(),\n    \"M2 Stacked LSTM\": metrics_m2[metric_cols].mean()\n}).T\n\nprint(\"\\nM0 vs M1 vs M2 — Macro Average Comparison:\")\ndisplay(comparison_all.round(4))\n\n# Step 7: Save results\nmetrics_m2.to_csv(\n    \"/kaggle/working/M2_Validation_Metrics.csv\",\n    index=False\n)\n\ncomparison_all.to_csv(\n    \"/kaggle/working/All_Models_Comparison.csv\"\n)\n\nprint(\"\\nEvaluated Time Points:\", len(y_true_m2))\nprint(\"All Model Metrics Saved Successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T16:56:18.936232Z","iopub.execute_input":"2026-10-11T16:56:18.936665Z","iopub.status.idle":"2026-10-11T16:56:41.642278Z","shell.execute_reply.started":"2026-10-11T16:56:18.936638Z","shell.execute_reply":"2026-10-11T16:56:41.641701Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 30 — M2 Evaluation and Three-Model Comparison\n\nTeeno models ko same subject-independent validation dataset par evaluate kiya. Dataset imbalanced hai, isliye Accuracy ke saath Balanced Accuracy, Precision, Recall, F1 aur ROC AUC bhi report kiye. ROC AUC predicted probabilities ki ranking quality measure karta hai, jabke F1 Precision aur Recall ka balance show karta hai.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport pandas as pd\n\nfrom sklearn.metrics import (\n    precision_score,\n    recall_score,\n    f1_score\n)\n\nthresholds_m2 = np.arange(0.02, 0.81, 0.02)\n\nthreshold_results_m2 = []\n\nprint(\"Optimizing M2 Classification Threshold...\")\n\nfor threshold in thresholds_m2:\n\n    predictions = (\n        y_prob_m2 >= threshold\n    ).astype(np.uint8)\n\n    threshold_results_m2.append({\n        \"Threshold\": round(float(threshold), 2),\n\n        \"Precision\": precision_score(\n            y_true_m2,\n            predictions,\n            average=\"macro\",\n            zero_division=0\n        ),\n\n        \"Recall\": recall_score(\n            y_true_m2,\n            predictions,\n            average=\"macro\",\n            zero_division=0\n        ),\n\n        \"F1\": f1_score(\n            y_true_m2,\n            predictions,\n            average=\"macro\",\n            zero_division=0\n        )\n    })\n\nthreshold_df_m2 = pd.DataFrame(\n    threshold_results_m2\n)\n\nbest_index_m2 = threshold_df_m2[\"F1\"].idxmax()\n\nbest_threshold_m2 = float(\n    threshold_df_m2.loc[best_index_m2, \"Threshold\"]\n)\n\nbest_f1_m2 = float(\n    threshold_df_m2.loc[best_index_m2, \"F1\"]\n)\n\nprint(\"\\nM2 Threshold Optimization Results:\")\ndisplay(threshold_df_m2.round(4))\n\nprint(\"\\nBest M2 Threshold:\", best_threshold_m2)\nprint(\"Best M2 Macro F1:\", round(best_f1_m2, 4))\n\n# Compare tuned F1 across all models\ntuned_comparison = pd.DataFrame({\n    \"Model\": [\n        \"M0 Simple RNN\",\n        \"M1 Weighted LSTM\",\n        \"M2 Stacked LSTM\"\n    ],\n\n    \"Best Threshold\": [\n        best_threshold_m0,\n        best_threshold_m1,\n        best_threshold_m2\n    ],\n\n    \"Best Macro F1\": [\n        float(threshold_df[\"F1\"].max()),\n        float(threshold_df_m1[\"F1\"].max()),\n        best_f1_m2\n    ],\n\n    \"ROC AUC\": [\n        metrics_m0[\"ROC AUC\"].mean(),\n        metrics_m1[\"ROC AUC\"].mean(),\n        metrics_m2[\"ROC AUC\"].mean()\n    ]\n})\n\nprint(\"\\nAll Models — Tuned Performance:\")\ndisplay(tuned_comparison.round(4))\n\n# Save results\nthreshold_df_m2.to_csv(\n    \"/kaggle/working/M2_Threshold_Results.csv\",\n    index=False\n)\n\ntuned_comparison.to_csv(\n    \"/kaggle/working/All_Models_Tuned_Comparison.csv\",\n    index=False\n)\n\nprint(\"\\nM2 Threshold Optimization Saved Successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T17:01:06.760793Z","iopub.execute_input":"2026-10-11T17:01:06.761085Z","iopub.status.idle":"2026-10-11T17:05:23.994331Z","shell.execute_reply.started":"2026-10-11T17:01:06.761062Z","shell.execute_reply":"2026-10-11T17:05:23.993607Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 31 — M2 Threshold Optimization and Final Model Comparison\n\nHumne threshold tuning use ki kyunki positive movement events dataset mein approximately 2.6% hain. Humne best macro F1 ke liye threshold select kiya. ROC AUC threshold-independent hai, isliye threshold change karne se ROC AUC improve nahi hota.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\n\n# Apply optimized M2 threshold\ny_pred_m2_tuned = (\n    y_prob_m2 >= best_threshold_m2\n).astype(np.uint8)\n\nfig, axes = plt.subplots(\n    2, 3,\n    figsize=(16, 9)\n)\n\nfor i, event in enumerate(EVENT_COLS):\n\n    cm = confusion_matrix(\n        y_true_m2[:, i],\n        y_pred_m2_tuned[:, i],\n        labels=[0, 1]\n    )\n\n    disp = ConfusionMatrixDisplay(\n        confusion_matrix=cm,\n        display_labels=[\"No Event\", \"Event\"]\n    )\n\n    disp.plot(\n        ax=axes.flat[i],\n        cmap=\"Blues\",\n        colorbar=False,\n        values_format=\"d\"\n    )\n\n    axes.flat[i].set_title(\n        event,\n        fontsize=11,\n        fontweight=\"bold\"\n    )\n\nplt.suptitle(\n    f\"M2 Stacked LSTM — Confusion Matrices (Threshold = {best_threshold_m2:.2f})\",\n    fontsize=15,\n    fontweight=\"bold\"\n)\n\nplt.tight_layout()\n\nplt.savefig(\n    \"/kaggle/working/M2_Confusion_Matrices.png\",\n    dpi=300,\n    bbox_inches=\"tight\"\n)\n\nplt.show()\n\nprint(\"Confusion Matrices Saved Successfully!\")\n\n# Show TP, TN, FP and FN as a table\nconfusion_results = []\n\nfor i, event in enumerate(EVENT_COLS):\n\n    tn, fp, fn, tp = confusion_matrix(\n        y_true_m2[:, i],\n        y_pred_m2_tuned[:, i],\n        labels=[0, 1]\n    ).ravel()\n\n    confusion_results.append({\n        \"Event\": event,\n        \"True Negative\": tn,\n        \"False Positive\": fp,\n        \"False Negative\": fn,\n        \"True Positive\": tp\n    })\n\nconfusion_df_m2 = pd.DataFrame(confusion_results)\n\nprint(\"\\nM2 Confusion Matrix Summary:\")\ndisplay(confusion_df_m2)\n\nconfusion_df_m2.to_csv(\n    \"/kaggle/working/M2_Confusion_Matrix_Summary.csv\",\n    index=False\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T17:07:05.728117Z","iopub.execute_input":"2026-10-11T17:07:05.728589Z","iopub.status.idle":"2026-10-11T17:07:09.689905Z","shell.execute_reply.started":"2026-10-11T17:07:05.728561Z","shell.execute_reply":"2026-10-11T17:07:09.689187Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 32 — Confusion Matrix Analysis\n\nHumne confusion matrices use ki taake class imbalance ke bawajood model ki event detection performance samajh sakein. True Positive correctly detected events hain, False Negative missed events hain aur False Positive false alarms represent karte hain.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import roc_curve, roc_auc_score\n\nplt.figure(figsize=(10, 8))\n\nauc_results_m2 = []\n\nfor i, event in enumerate(EVENT_COLS):\n\n    y_true_event = y_true_m2[:, i]\n    y_prob_event = y_prob_m2[:, i]\n\n    fpr, tpr, _ = roc_curve(\n        y_true_event,\n        y_prob_event,\n        drop_intermediate=True\n    )\n\n    auc_value = roc_auc_score(\n        y_true_event,\n        y_prob_event\n    )\n\n    plt.plot(\n        fpr,\n        tpr,\n        linewidth=2,\n        label=f\"{event} (AUC = {auc_value:.4f})\"\n    )\n\n    auc_results_m2.append({\n        \"Event\": event,\n        \"ROC AUC\": auc_value\n    })\n\n# Random classifier reference line\nplt.plot(\n    [0, 1],\n    [0, 1],\n    linestyle=\"--\",\n    color=\"gray\",\n    label=\"Random Classifier (AUC = 0.50)\"\n)\n\nplt.xlabel(\"False Positive Rate\")\nplt.ylabel(\"True Positive Rate\")\nplt.title(\"M2 Stacked LSTM — ROC Curves\")\nplt.legend(loc=\"lower right\")\nplt.grid(alpha=0.3)\nplt.tight_layout()\n\nplt.savefig(\n    \"/kaggle/working/M2_ROC_Curves.png\",\n    dpi=300,\n    bbox_inches=\"tight\"\n)\n\nplt.show()\n\nauc_df_m2 = pd.DataFrame(auc_results_m2)\n\nprint(\"\\nM2 Event-wise ROC AUC:\")\ndisplay(auc_df_m2.round(4))\n\nprint(\n    \"\\nMacro ROC AUC:\",\n    round(auc_df_m2[\"ROC AUC\"].mean(), 4)\n)\n\nauc_df_m2.to_csv(\n    \"/kaggle/working/M2_ROC_AUC_Results.csv\",\n    index=False\n)\n\nprint(\"\\nROC Curves Saved Successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T17:08:06.542568Z","iopub.execute_input":"2026-10-11T17:08:06.542855Z","iopub.status.idle":"2026-10-11T17:08:17.744836Z","shell.execute_reply.started":"2026-10-11T17:08:06.54283Z","shell.execute_reply":"2026-10-11T17:08:17.743969Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 33 — ROC Curve Analysis\n\n ROC AUC threshold-independent evaluation metric hai. Iska value 0.5 random ranking ko represent karta hai, jabke 1.0 perfect discrimination ko represent karta hai. Humne six events ka ROC AUC separately calculate karke unka macro average report kiya.\n","metadata":{}},{"cell_type":"code","source":"\nimport zipfile\nimport pandas as pd\nimport os\n\n# Open test and sample submission ZIPs\ntest_zip = (\n    \"/kaggle/input/competitions/\"\n    \"grasp-and-lift-eeg-detection/test.zip\"\n)\n\nsubmission_zip = (\n    \"/kaggle/input/competitions/\"\n    \"grasp-and-lift-eeg-detection/sample_submission.csv.zip\"\n)\n\nwith zipfile.ZipFile(test_zip, \"r\") as z:\n    test_files = sorted([\n        name for name in z.namelist()\n        if name.endswith(\"_data.csv\")\n    ])\n\nprint(\"Total Test Files:\", len(test_files))\nprint(\"\\nFirst 5 Test Files:\")\nfor name in test_files[:5]:\n    print(name)\n\nwith zipfile.ZipFile(submission_zip, \"r\") as z:\n    submission_files = [\n        name for name in z.namelist()\n        if name.endswith(\".csv\")\n    ]\n\n    print(\"\\nSubmission Files:\", submission_files)\n\n    with z.open(submission_files[0]) as f:\n        submission_sample = pd.read_csv(\n            f,\n            nrows=5\n        )\n\nprint(\"\\nSample Submission Preview:\")\ndisplay(submission_sample)\n\nprint(\"\\nSubmission Columns:\")\nprint(submission_sample.columns.tolist())\n\nprint(\"\\nExpected Event Columns:\")\nprint(EVENT_COLS)\n\nprint(\"\\nColumn Alignment Check:\")\nprint(\n    submission_sample.columns.tolist()[1:]\n    == EVENT_COLS\n)\n\n# Verify test recording structure\nwith zipfile.ZipFile(test_zip, \"r\") as z:\n    with z.open(test_files[0]) as f:\n        test_sample = pd.read_csv(\n            f,\n            nrows=5\n        )\n\nprint(\"\\nTest EEG Preview:\")\ndisplay(test_sample)\n\nprint(\"\\nTest EEG Shape:\", test_sample.shape)\nprint(\"Test EEG Channels:\", len(test_sample.columns) - 1)\nprint(\"Test Columns Match Training:\", (\n    test_sample.columns.tolist()[1:] == EEG_COLS\n))\n\nprint(\"\\nSubmission Format Verification Complete!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T17:09:12.44877Z","iopub.execute_input":"2026-10-11T17:09:12.449187Z","iopub.status.idle":"2026-10-11T17:09:12.547701Z","shell.execute_reply.started":"2026-10-11T17:09:12.449158Z","shell.execute_reply":"2026-10-11T17:09:12.546911Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 34 — Kaggle Submission Format Verification\n\nHumne competition ke provided sample submission ko reference banaya. Har test EEG time point ke liye six movement-event probabilities predict karni hain. Humne ensure kiya ke output columns competition ke required format ke according hon.\n","metadata":{}},{"cell_type":"code","source":"\nimport numpy as np\nimport pandas as pd\nimport zipfile\n\ndef predict_eeg_recording(model, eeg_array, seq_len=128):\n    \"\"\"\n    Predict six event probabilities for every EEG time point.\n\n    Uses chronological, non-overlapping windows.\n    Handles the final incomplete window with zero padding.\n    \"\"\"\n\n    n_rows = len(eeg_array)\n\n    if n_rows == 0:\n        return np.empty((0, 6), dtype=np.float32)\n\n    predictions = np.empty(\n        (n_rows, 6),\n        dtype=np.float32\n    )\n\n    # Process a manageable number of windows per batch\n    windows_per_batch = 256\n    points_per_batch = windows_per_batch * seq_len\n\n    for start in range(0, n_rows, points_per_batch):\n\n        end = min(start + points_per_batch, n_rows)\n\n        chunk = eeg_array[start:end]\n\n        original_length = len(chunk)\n\n        # Pad final incomplete sequence\n        pad_length = (-original_length) % seq_len\n\n        if pad_length > 0:\n            chunk = np.pad(\n                chunk,\n                ((0, pad_length), (0, 0)),\n                mode=\"constant\",\n                constant_values=0\n            )\n\n        X_batch = chunk.reshape(\n            -1,\n            seq_len,\n            32\n        ).astype(np.float32)\n\n        batch_predictions = model(\n            X_batch,\n            training=False\n        ).numpy()\n\n        batch_predictions = batch_predictions.reshape(\n            -1, 6\n        )\n\n        # Remove predictions for padding\n        predictions[start:end] = (\n            batch_predictions[:original_length]\n        )\n\n    return predictions\n\n\n# Test pipeline using one recording\nwith zipfile.ZipFile(test_zip, \"r\") as z:\n    with z.open(test_files[0]) as f:\n        test_recording = pd.read_csv(f)\n\ntest_ids = test_recording[\"id\"].copy()\n\ntest_X = test_recording[\n    EEG_COLS\n].to_numpy(dtype=np.float32)\n\n# Apply training-only normalization\ntest_X = (\n    test_X - eeg_mean\n) / eeg_std\n\ntest_X = test_X.astype(np.float32)\n\nassert np.isfinite(test_X).all()\n\n# Test M2 inference\ntest_probabilities = predict_eeg_recording(\n    m2,\n    test_X,\n    seq_len=SEQ_LEN\n)\n\nprint(\"Test Recording:\", test_files[0])\nprint(\"Original EEG Rows:\", len(test_recording))\nprint(\"Prediction Shape:\", test_probabilities.shape)\n\nprint(\n    \"All Probabilities Valid:\",\n    np.isfinite(test_probabilities).all()\n    and (test_probabilities >= 0).all()\n    and (test_probabilities <= 1).all()\n)\n\nassert test_probabilities.shape == (\n    len(test_recording), 6\n)\n\n# Build sample output for alignment verification\ntest_prediction_preview = pd.DataFrame(\n    test_probabilities[:5],\n    columns=EVENT_COLS\n)\n\ntest_prediction_preview.insert(\n    0,\n    \"id\",\n    test_ids.iloc[:5].to_numpy()\n)\n\nprint(\"\\nPrediction Preview:\")\ndisplay(test_prediction_preview.round(5))\n\nprint(\"\\nFirst Original ID:\", test_ids.iloc[0])\nprint(\"First Prediction ID:\", test_prediction_preview[\"id\"].iloc[0])\n\nprint(\"\\nTest Inference Pipeline Verified!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T17:11:09.982749Z","iopub.execute_input":"2026-10-11T17:11:09.983588Z","iopub.status.idle":"2026-10-11T17:11:10.595997Z","shell.execute_reply.started":"2026-10-11T17:11:09.983555Z","shell.execute_reply":"2026-10-11T17:11:10.595208Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 35 — Test EEG Inference Pipeline\n\nHumne test data ko training-set mean aur standard deviation se normalize kiya. Phir unidirectional LSTM se chronological EEG sequences par inference perform ki. Final incomplete sequence ko padding ke through handle kiya, aur ensure kiya ke har input time point ki exactly six predictions generate hon.\n","metadata":{}},{"cell_type":"code","source":"\nimport os\nimport gc\nimport zipfile\nimport numpy as np\nimport pandas as pd\n\nOUTPUT_DIR = \"/kaggle/working/submissions\"\nos.makedirs(OUTPUT_DIR, exist_ok=True)\n\nmodels_to_submit = {\n    \"M0_Simple_RNN\": m0,\n    \"M1_Weighted_LSTM\": m1,\n    \"M2_Stacked_LSTM\": m2\n}\n\nsubmission_paths = {\n    name: os.path.join(\n        OUTPUT_DIR,\n        f\"{name}_submission.csv\"\n    )\n    for name in models_to_submit\n}\n\n# Remove old partial files if rerunning this cell\nfor path in submission_paths.values():\n    if os.path.exists(path):\n        os.remove(path)\n\ntotal_rows = 0\n\nprint(\"Generating Kaggle Submissions...\")\nprint(\"Total Test Files:\", len(test_files))\n\nwith zipfile.ZipFile(test_zip, \"r\") as archive:\n\n    for file_index, filename in enumerate(test_files, start=1):\n\n        with archive.open(filename) as f:\n            test_df = pd.read_csv(f)\n\n        ids = test_df[\"id\"].to_numpy()\n\n        X = test_df[EEG_COLS].to_numpy(\n            dtype=np.float32\n        )\n\n        # Normalize using training statistics\n        X = ((X - eeg_mean) / eeg_std).astype(\n            np.float32\n        )\n\n        assert np.isfinite(X).all()\n\n        for model_name, model in models_to_submit.items():\n\n            probabilities = predict_eeg_recording(\n                model,\n                X,\n                seq_len=SEQ_LEN\n            )\n\n            assert probabilities.shape == (\n                len(ids), 6\n            )\n\n            assert np.isfinite(probabilities).all()\n\n            assert (\n                (probabilities >= 0).all()\n                and (probabilities <= 1).all()\n            )\n\n            output_df = pd.DataFrame(\n                probabilities,\n                columns=EVENT_COLS\n            )\n\n            output_df.insert(0, \"id\", ids)\n\n            output_df.to_csv(\n                submission_paths[model_name],\n                mode=\"a\",\n                header=(file_index == 1),\n                index=False,\n                float_format=\"%.7f\"\n            )\n\n            del probabilities, output_df\n\n        total_rows += len(ids)\n\n        print(\n            f\"[{file_index}/{len(test_files)}] \"\n            f\"{filename} — {len(ids):,} rows\"\n        )\n\n        del test_df, X, ids\n        gc.collect()\n\nprint(\"\\nAll Test Recordings Processed!\")\nprint(\"Total Prediction Rows:\", f\"{total_rows:,}\")\n\nprint(\"\\nGenerated Submission Files:\")\n\nfor model_name, path in submission_paths.items():\n\n    file_size_mb = os.path.getsize(path) / (1024 ** 2)\n\n    print(\n        f\"{model_name}: \"\n        f\"{file_size_mb:.2f} MB\"\n    )\n\n    print(\"Saved:\", path)\n\nprint(\"\\nThree Kaggle Submission CSVs Generated Successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T17:11:55.004412Z","iopub.execute_input":"2026-10-11T17:11:55.004751Z","iopub.status.idle":"2026-10-11T17:14:20.244176Z","shell.execute_reply.started":"2026-10-11T17:11:55.004726Z","shell.execute_reply":"2026-10-11T17:14:20.243552Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 36 — Kaggle Submission Generation\n\nTest EEG signals ko training data ki normalization statistics se preprocess kiya. Har time point ke liye six event probabilities generate ki aur original IDs ke saath CSV mein save ki. Humne thresholding apply nahi ki kyunki competition ROC AUC metric use karti hai, jisme continuous probability scores required hote hain.\n","metadata":{}},{"cell_type":"code","source":"\nimport os\nimport gc\nimport sqlite3\nimport zipfile\nimport pandas as pd\nimport numpy as np\n\n# Read expected IDs from sample submission\nwith zipfile.ZipFile(submission_zip, \"r\") as z:\n    with z.open(\"sample_submission.csv\") as f:\n        expected_ids = pd.read_csv(\n            f,\n            usecols=[\"id\"]\n        )[\"id\"]\n\nexpected_count = len(expected_ids)\n\nprint(\"Expected Submission Rows:\", expected_count)\n\n# Create ID-to-position mapping in memory\nexpected_index = pd.Index(expected_ids)\n\nassert expected_index.is_unique, (\n    \"Sample submission contains duplicate IDs!\"\n)\n\nfor model_name, path in submission_paths.items():\n\n    print(f\"\\nValidating {model_name}...\")\n\n    ordered_path = path.replace(\n        \".csv\",\n        \"_ordered.csv\"\n    )\n\n    # Disk-backed temporary database to avoid\n    # loading the entire prediction CSV into RAM\n    db_path = os.path.join(\n        OUTPUT_DIR,\n        f\"{model_name}_temp.sqlite\"\n    )\n\n    if os.path.exists(db_path):\n        os.remove(db_path)\n\n    conn = sqlite3.connect(db_path)\n\n    conn.execute(\"\"\"\n        CREATE TABLE predictions (\n            id TEXT PRIMARY KEY,\n            HandStart REAL,\n            FirstDigitTouch REAL,\n            BothStartLoadPhase REAL,\n            LiftOff REAL,\n            ReplaceEvent REAL,\n            BothReleased REAL\n        )\n    \"\"\")\n\n    total_loaded = 0\n\n    for chunk in pd.read_csv(\n        path,\n        chunksize=50000\n    ):\n\n        assert chunk.columns.tolist() == (\n            [\"id\"] + EVENT_COLS\n        )\n\n        assert chunk[\"id\"].notna().all()\n\n        assert np.isfinite(\n            chunk[EVENT_COLS].to_numpy()\n        ).all()\n\n        assert (\n            chunk[EVENT_COLS]\n            .ge(0)\n            .all()\n            .all()\n        )\n\n        assert (\n            chunk[EVENT_COLS]\n            .le(1)\n            .all()\n            .all()\n        )\n\n        records = list(\n            chunk.itertuples(\n                index=False,\n                name=None\n            )\n        )\n\n        conn.executemany(\n            \"\"\"\n            INSERT INTO predictions VALUES\n            (?, ?, ?, ?, ?, ?, ?)\n            \"\"\",\n            records\n        )\n\n        total_loaded += len(chunk)\n\n    conn.commit()\n\n    assert total_loaded == expected_count, (\n        f\"Row count mismatch for {model_name}\"\n    )\n\n    print(\"Rows Verified:\", total_loaded)\n\n    # Write output in exact sample submission order\n    with open(ordered_path, \"w\") as output_file:\n\n        output_file.write(\n            \",\".join([\"id\"] + EVENT_COLS) + \"\\n\"\n        )\n\n        batch_size = 5000\n\n        for start in range(\n            0,\n            expected_count,\n            batch_size\n        ):\n\n            batch_ids = expected_ids.iloc[\n                start:start + batch_size\n            ].tolist()\n\n            placeholders = \",\".join(\n                [\"?\"] * len(batch_ids)\n            )\n\n            query = f\"\"\"\n                SELECT\n                    id,\n                    HandStart,\n                    FirstDigitTouch,\n                    BothStartLoadPhase,\n                    LiftOff,\n                    ReplaceEvent,\n                    BothReleased\n                FROM predictions\n                WHERE id IN ({placeholders})\n            \"\"\"\n\n            rows = conn.execute(\n                query,\n                batch_ids\n            ).fetchall()\n\n            lookup = {\n                row[0]: row[1:]\n                for row in rows\n            }\n\n            assert len(lookup) == len(batch_ids), (\n                \"Missing prediction IDs!\"\n            )\n\n            ordered_rows = [\n                (sample_id,) + lookup[sample_id]\n                for sample_id in batch_ids\n            ]\n\n            ordered_df = pd.DataFrame(\n                ordered_rows,\n                columns=[\"id\"] + EVENT_COLS\n            )\n\n            ordered_df.to_csv(\n                output_file,\n                header=False,\n                index=False,\n                float_format=\"%.7f\"\n            )\n\n    conn.close()\n    os.remove(db_path)\n\n    # Replace unsorted CSV with verified CSV\n    os.replace(ordered_path, path)\n\n    print(\"ID Order: Verified\")\n    print(\"Columns: Verified\")\n    print(\"Probabilities: Verified\")\n    print(\n        \"Final File Size:\",\n        round(\n            os.path.getsize(path) / (1024 ** 2),\n            2\n        ),\n        \"MB\"\n    )\n\n    gc.collect()\n\nprint(\"\\nALL THREE SUBMISSIONS VERIFIED SUCCESSFULLY!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T17:17:48.572093Z","iopub.execute_input":"2026-10-11T17:17:48.572931Z","iopub.status.idle":"2026-10-11T17:20:34.263516Z","shell.execute_reply.started":"2026-10-11T17:17:48.572901Z","shell.execute_reply":"2026-10-11T17:20:34.262676Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n### Cell 37 — Final Kaggle Submission Validation\n\nFinal submission files mein unique IDs, expected row count, six event probability columns aur sample submission ki exact row order verify ki. Isse competition submission ka structural correctness ensure hua.\n","metadata":{}},{"cell_type":"code","source":"\nimport os\n\nfolder = \"/kaggle/working/submissions\"\n\nrename_files = {\n    \"M2_Stacked_LSTM_submission.csv\": \"submission.csv\",\n    \"M1_Weighted_LSTM_submission.csv\": \"m1_submission.csv\",\n    \"M0_Simple_RNN_submission.csv\": \"m0_submission.csv\"\n}\n\nfor old_name, new_name in rename_files.items():\n    old_path = os.path.join(folder, old_name)\n    new_path = os.path.join(folder, new_name)\n\n    if os.path.exists(old_path):\n        os.rename(old_path, new_path)\n        print(f\"Renamed: {old_name} → {new_name}\")\n    elif os.path.exists(new_path):\n        print(f\"Already renamed: {new_name}\")\n    else:\n        print(f\"File not found: {old_name}\")\n\nprint(\"\\nFinal Submission Files:\")\nfor filename in [\"submission.csv\", \"m1_submission.csv\", \"m0_submission.csv\"]:\n    path = os.path.join(folder, filename)\n    print(filename, \"—\", \"Ready\" if os.path.exists(path) else \"Missing\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-11T17:21:55.49475Z","iopub.execute_input":"2026-10-11T17:21:55.495539Z","iopub.status.idle":"2026-10-11T17:21:55.502497Z","shell.execute_reply.started":"2026-10-11T17:21:55.495508Z","shell.execute_reply":"2026-10-11T17:21:55.501647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}