{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":59093,"databundleVersionId":7469972,"sourceType":"competition"}],"dockerImageVersionId":31012,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport pyarrow.parquet as pq\nimport os\nimport scipy.signal as signal\nimport random\nfrom sklearn.decomposition import FastICA\nimport pywt\nimport matplotlib.pyplot as plt\nimport io\nfrom PIL import Image\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:31.554930Z","iopub.execute_input":"2025-04-15T10:23:31.555258Z","iopub.status.idle":"2025-04-15T10:23:33.153888Z","shell.execute_reply.started":"2025-04-15T10:23:31.555230Z","shell.execute_reply":"2025-04-15T10:23:33.152808Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load train.csv\ntrain_df = pd.read_csv('/kaggle/input/hms-harmful-brain-activity-classification/train.csv')\nprint(train_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:33.155860Z","iopub.execute_input":"2025-04-15T10:23:33.156411Z","iopub.status.idle":"2025-04-15T10:23:33.434764Z","shell.execute_reply.started":"2025-04-15T10:23:33.156382Z","shell.execute_reply":"2025-04-15T10:23:33.433732Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def butter_bandpass(lowcut, highcut, fs, order=4):\n    nyq = 0.5 * fs\n    low = lowcut / nyq\n    high = highcut / nyq\n    return signal.butter(order, [low, high], btype='band')    \n\ndef apply_filter(data, lowcut=0.5, highcut=50.0, fs=200, order=4):\n    b, a = butter_bandpass(lowcut, highcut, fs, order)\n    return signal.filtfilt(b, a, data)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:33.435833Z","iopub.execute_input":"2025-04-15T10:23:33.436103Z","iopub.status.idle":"2025-04-15T10:23:33.443560Z","shell.execute_reply.started":"2025-04-15T10:23:33.436081Z","shell.execute_reply":"2025-04-15T10:23:33.442346Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def preprocess_eeg_and_apply_filter(eeg_df):\n    eeg_df = eeg_df.drop(columns=['EKG'])  # Skip EKG\n    for col in eeg_df.columns:\n        eeg_df[col] = apply_filter(eeg_df[col])\n    return eeg_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:33.446083Z","iopub.execute_input":"2025-04-15T10:23:33.446420Z","iopub.status.idle":"2025-04-15T10:23:33.468355Z","shell.execute_reply.started":"2025-04-15T10:23:33.446384Z","shell.execute_reply":"2025-04-15T10:23:33.467364Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"montage_pairs = [\n    # Parasagittal chains (left hemisphere)\n    (\"Fp1\", \"F3\"), \n    (\"F3\", \"C3\"), \n    (\"C3\", \"P3\"), \n    (\"P3\", \"O1\"),\n    \n    # Parasagittal chains (right hemisphere)\n    (\"Fp2\", \"F4\"), \n    (\"F4\", \"C4\"), \n    (\"C4\", \"P4\"), \n    (\"P4\", \"O2\"),\n    \n    # Central chain\n    (\"Fz\", \"Cz\"), \n    (\"Cz\", \"Pz\"),\n    \n    # Temporal chains (left side: Fp1 → F7 → T3 → T5 → O1)\n    (\"Fp1\", \"F7\"),\n    (\"F7\", \"T3\"),\n    (\"T3\", \"T5\"),\n    (\"T5\", \"O1\"),\n    \n    # Temporal chains (right side: Fp2 → F8 → T4 → T6 → O2)\n    (\"Fp2\", \"F8\"),\n    (\"F8\", \"T4\"),\n    (\"T4\", \"T6\"),\n    (\"T6\", \"O2\")\n]\n\ndef apply_double_banana_montage(eeg_df: pd.DataFrame):\n    montage_df = pd.DataFrame()\n    for ch1, ch2 in montage_pairs:\n        montage_df[f\"{ch1}-{ch2}\"] = eeg_df[ch1] - eeg_df[ch2]\n    return montage_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:33.469436Z","iopub.execute_input":"2025-04-15T10:23:33.469709Z","iopub.status.idle":"2025-04-15T10:23:33.490520Z","shell.execute_reply.started":"2025-04-15T10:23:33.469688Z","shell.execute_reply":"2025-04-15T10:23:33.489474Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def apply_ica(eeg_df: pd.DataFrame):    \n    ica = FastICA(n_components=eeg_df.shape[1], random_state=42, max_iter=1000)\n    try:\n        components = ica.fit_transform(eeg_df)\n        cleaned = ica.inverse_transform(components)\n        return pd.DataFrame(cleaned, columns=eeg_df.columns)\n    except Exception as e:\n        print(f\"ICA failed: {e}\")\n        return eeg_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:33.491510Z","iopub.execute_input":"2025-04-15T10:23:33.491777Z","iopub.status.idle":"2025-04-15T10:23:33.510643Z","shell.execute_reply.started":"2025-04-15T10:23:33.491756Z","shell.execute_reply":"2025-04-15T10:23:33.509845Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def crop_middle_segment(eeg_df, duration_sec=50, fs=200):\n    num_samples = duration_sec * fs\n    start = (len(eeg_df) - num_samples) // 2\n    return eeg_df.iloc[start:start+num_samples].reset_index(drop=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:33.511566Z","iopub.execute_input":"2025-04-15T10:23:33.511798Z","iopub.status.idle":"2025-04-15T10:23:33.536212Z","shell.execute_reply.started":"2025-04-15T10:23:33.511780Z","shell.execute_reply":"2025-04-15T10:23:33.535273Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def compute_power_matrix(signal, scales=np.arange(1, 64), wavelet='morl'):\n    coefficients, _ = pywt.cwt(signal, scales, wavelet)\n    power = (np.abs(coefficients)) ** 2\n    return power\n\ndef compute_group_spectrogram(montage_df, group_channels, scales=np.arange(1, 64), wavelet='morl'):\n    power_matrices = []\n    for ch in group_channels:\n        if ch in montage_df.columns:\n            signal = montage_df[ch].values\n            power = compute_power_matrix(signal, scales, wavelet)\n            power_matrices.append(power)\n    if not power_matrices:\n        return None\n    # Average pixel-wise over the computed power matrices\n    avg_power = np.mean(np.array(power_matrices), axis=0)\n    return avg_power","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:33.537564Z","iopub.execute_input":"2025-04-15T10:23:33.537906Z","iopub.status.idle":"2025-04-15T10:23:33.558119Z","shell.execute_reply.started":"2025-04-15T10:23:33.537869Z","shell.execute_reply":"2025-04-15T10:23:33.557088Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def display_power_matrix_as_image(power_matrix, signal_length, fs, scales, wavelet, title=\"\", figsize=(6,4)):\n    \n    # Total time span in seconds\n    T = signal_length / fs\n    \n    freq_axis = pywt.scale2frequency(wavelet, scales) * fs\n    \n    extent = [0, T, freq_axis[-1], freq_axis[0]]\n\n    plt.figure(figsize=figsize)\n    plt.imshow(power_matrix, extent=extent, cmap='jet', aspect='auto', origin='lower')\n    plt.xlabel(\"Time (s)\")\n    plt.ylabel(\"Frequency (Hz)\")\n    plt.title(title)\n    plt.colorbar()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:33.559277Z","iopub.execute_input":"2025-04-15T10:23:33.559619Z","iopub.status.idle":"2025-04-15T10:23:33.578351Z","shell.execute_reply.started":"2025-04-15T10:23:33.559596Z","shell.execute_reply":"2025-04-15T10:23:33.577343Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"chain_groups = {\n    \"LL\": [\"Fp1-F7\", \"F7-T3\", \"T3-T5\", \"T5-O1\"],  # Left Temporal Chain\n    \"RL\": [\"Fp2-F8\", \"F8-T4\", \"T4-T6\", \"T6-O2\"],  # Right Temporal Chain\n    \"LP\": [\"Fp1-F3\", \"F3-C3\", \"C3-P3\", \"P3-O1\"],  # Left Parasagittal Chain\n    \"RP\": [\"Fp2-F4\", \"F4-C4\", \"C4-P4\", \"P4-O2\"]   # Right Parasagittal Chain\n}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:33.580488Z","iopub.execute_input":"2025-04-15T10:23:33.580742Z","iopub.status.idle":"2025-04-15T10:23:33.602470Z","shell.execute_reply.started":"2025-04-15T10:23:33.580723Z","shell.execute_reply":"2025-04-15T10:23:33.601508Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"eeg_id = 582999 #568657 #778705 #751790 #568657 #582999\neeg_path = f\"/kaggle/input/hms-harmful-brain-activity-classification/train_eegs/{eeg_id}.parquet\"\neeg_df = pd.read_parquet(eeg_path)\n\nfiltered_eeg = preprocess_eeg_and_apply_filter(eeg_df)\n# print(filtered_eeg.head())\nmontaged_df = apply_double_banana_montage(filtered_eeg)\n\nmontaged_ica = apply_ica(montaged_df)\n\nmiddle_segment = crop_middle_segment(montaged_ica)\n\nscales = np.arange(1, 64)\nwavelet = 'morl'\n\nspectrogram_results = {}\n\nfs=200\n\nfor group_name, channels in chain_groups.items():\n    power_matrix = compute_group_spectrogram(middle_segment, channels, scales=scales, wavelet=wavelet)\n    if power_matrix is not None:\n        spectrogram_results[group_name] = power_matrix\n        display_power_matrix_as_image(\n            power_matrix,\n            signal_length=middle_segment.shape[0],\n            fs=fs,\n            scales=scales,\n            wavelet=wavelet,\n            title=f\"{group_name} Spectrogram\"\n        )\n    else:\n        print(f\"No valid channels found for group {group_name}.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:33.603417Z","iopub.execute_input":"2025-04-15T10:23:33.603713Z","iopub.status.idle":"2025-04-15T10:23:40.899531Z","shell.execute_reply.started":"2025-04-15T10:23:33.603692Z","shell.execute_reply":"2025-04-15T10:23:40.898376Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sampling_rate = 200\nn_samples_5sec = 5 * sampling_rate\n\ndf = montaged_ica\n\neeg_df_first_5sec = df.iloc[:n_samples_5sec]\n\n# Plot settings\nplt.figure(figsize=(15, 8))\nn_channels = len(df.columns) \ny_offsets = [i * 300 for i in range(n_channels)]\n\n# Plot each EEG channel\nfor i, col in enumerate(df.columns[:n_channels]):\n    plt.plot(\n        eeg_df_first_5sec.index / sampling_rate,\n        eeg_df_first_5sec[col] + y_offsets[i],\n        linewidth=1,\n    )\n\nplt.yticks(y_offsets, df.columns[:n_channels])\nplt.xlabel(\"Time (seconds)\")\nplt.title(f\"EEG {eeg_id} - First 5 Seconds\")\nplt.grid(True, alpha=0.3)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:40.900635Z","iopub.execute_input":"2025-04-15T10:23:40.900925Z","iopub.status.idle":"2025-04-15T10:23:41.233059Z","shell.execute_reply.started":"2025-04-15T10:23:40.900904Z","shell.execute_reply":"2025-04-15T10:23:41.232183Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = montaged_df\n\neeg_df_first_5sec = df.iloc[:n_samples_5sec]\n\n# Plot settings\nplt.figure(figsize=(15, 8))\nn_channels = len(df.columns) \ny_offsets = [i * 300 for i in range(n_channels)]\n\n# Plot each EEG channel\nfor i, col in enumerate(df.columns[:n_channels]):\n    plt.plot(\n        eeg_df_first_5sec.index / sampling_rate,\n        eeg_df_first_5sec[col] + y_offsets[i],\n        linewidth=1,\n    )\n\nplt.yticks(y_offsets, df.columns[:n_channels])\nplt.xlabel(\"Time (seconds)\")\nplt.title(f\"EEG {eeg_id} - First 5 Seconds\")\nplt.grid(True, alpha=0.3)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-15T10:23:41.234098Z","iopub.execute_input":"2025-04-15T10:23:41.234427Z","iopub.status.idle":"2025-04-15T10:23:41.578013Z","shell.execute_reply.started":"2025-04-15T10:23:41.234401Z","shell.execute_reply":"2025-04-15T10:23:41.577044Z"}},"outputs":[],"execution_count":null}]}