{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":59093,"databundleVersionId":7469972,"sourceType":"competition"},{"sourceId":7392775,"sourceType":"datasetVersion","datasetId":4297782},{"sourceId":7447509,"sourceType":"datasetVersion","datasetId":4334995}],"dockerImageVersionId":30635,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pywt\nimport pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom matplotlib.ticker import MaxNLocator\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import LSTM, Dense, Dropout, BatchNormalization, Conv2D, MaxPooling2D, GlobalAveragePooling2D\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.optimizers import Adam\nfrom sklearn.preprocessing import LabelEncoder, RobustScaler\nfrom sklearn.model_selection import train_test_split, StratifiedKFold\nfrom sklearn.metrics import log_loss, confusion_matrix, f1_score","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:00:15.404132Z","iopub.execute_input":"2024-02-19T09:00:15.404394Z","iopub.status.idle":"2024-02-19T09:00:30.785576Z","shell.execute_reply.started":"2024-02-19T09:00:15.404370Z","shell.execute_reply":"2024-02-19T09:00:30.784385Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.environ[\"CUDA_VISIBLE_DEVICES\"]=\"0,1\"\n\n# USE MULTIPLE GPUS\ngpus = tf.config.list_physical_devices('GPU')\nif len(gpus)<=1: \n    strategy = tf.distribute.OneDeviceStrategy(device=\"/gpu:0\")\n    print(f'Using {len(gpus)} GPU')\nelse: \n    strategy = tf.distribute.MirroredStrategy()\n    print(f'Using {len(gpus)} GPUs')","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:00:30.787765Z","iopub.execute_input":"2024-02-19T09:00:30.788527Z","iopub.status.idle":"2024-02-19T09:00:32.166200Z","shell.execute_reply.started":"2024-02-19T09:00:30.788486Z","shell.execute_reply":"2024-02-19T09:00:32.165171Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv('/kaggle/input/hms-harmful-brain-activity-classification/train.csv')\ntest_df = pd.read_csv('/kaggle/input/hms-harmful-brain-activity-classification/test.csv')\nsubmission = pd.read_csv('/kaggle/input/hms-harmful-brain-activity-classification/sample_submission.csv')\n\nspectrograms = np.load('/kaggle/input/brain-spectrograms/specs.npy',allow_pickle=True)","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:00:32.167170Z","iopub.execute_input":"2024-02-19T09:00:32.167446Z","iopub.status.idle":"2024-02-19T09:01:25.772368Z","shell.execute_reply.started":"2024-02-19T09:00:32.167423Z","shell.execute_reply":"2024-02-19T09:01:25.771383Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display(train_df.head())\ndisplay(test_df.head())","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:01:25.774705Z","iopub.execute_input":"2024-02-19T09:01:25.775055Z","iopub.status.idle":"2024-02-19T09:01:25.807042Z","shell.execute_reply.started":"2024-02-19T09:01:25.775028Z","shell.execute_reply":"2024-02-19T09:01:25.806151Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_votes = train_df.columns[-6:]\n\ntrain = train_df.groupby('eeg_id')[['spectrogram_id','spectrogram_label_offset_seconds', 'patient_id' ,'expert_consensus']].agg(\n    {'spectrogram_id': 'first',\n     'spectrogram_label_offset_seconds': ['min', 'max'],\n     'patient_id': 'first',\n     'expert_consensus': 'first',\n    })\n\ntrain.columns = ['spec_id','spec_offset_min', 'spec_offset_max', 'patient_id', 'target']\n\ntmp = train_df.groupby('eeg_id')[train_votes].agg('sum') # get sum per vote for each eeg\ntmp[train_votes] = tmp[train_votes].div(tmp[train_votes].sum(axis=1), axis=0) # convert into probabilities\n\ntrain[train_votes] = tmp\ntrain = train[[col for col in train if col != 'target'] + ['target']] # put target variable at the end for more readability\ntrain = train.reset_index()\n\ndisplay(train.head())","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:01:25.808193Z","iopub.execute_input":"2024-02-19T09:01:25.808461Z","iopub.status.idle":"2024-02-19T09:01:25.899382Z","shell.execute_reply.started":"2024-02-19T09:01:25.808438Z","shell.execute_reply":"2024-02-19T09:01:25.898449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def maddest(d, axis=None):\n    return np.mean(np.absolute(d - np.mean(d, axis)), axis)\n\ndef denoise(x, wavelet='haar', level=1):\n    ret = {key:[] for key in x.columns}\n    \n    for pos in x.columns:\n        coeff = pywt.wavedec(x[pos], wavelet, mode=\"per\")\n        sigma = (1/0.6745) * maddest(coeff[-level])\n\n        uthresh = sigma * np.sqrt(2*np.log(len(x)))\n        coeff[1:] = (pywt.threshold(i, value=uthresh, mode='hard') for i in coeff[1:])\n\n        ret[pos]=pywt.waverec(coeff, wavelet, mode='per')\n    \n    return pd.DataFrame(ret)\n\n# eeg_denoised = denoise(eeg, wavelet=\"db8\")","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:01:25.900560Z","iopub.execute_input":"2024-02-19T09:01:25.900947Z","iopub.status.idle":"2024-02-19T09:01:25.909404Z","shell.execute_reply.started":"2024-02-19T09:01:25.900912Z","shell.execute_reply":"2024-02-19T09:01:25.908358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 2366870, 2259539799\ndef eeg_info(eeg_id=36718960):\n    eeg_df = train_df[train_df[\"eeg_id\"] == eeg_id].reset_index(drop=True)\n    spec = pd.read_parquet(f'/kaggle/input/hms-harmful-brain-activity-classification/train_spectrograms/{eeg_df[\"spectrogram_id\"].values[0]}.parquet')    \n\n    eeg = pd.read_parquet(f'/kaggle/input/hms-harmful-brain-activity-classification/train_eegs/{eeg_id}.parquet')\n    \n    display(eeg_df)\n    \n    # PLOT THE SUB EEG TIME REPRESENTATION\n    plt.figure(figsize=(20, min(10, len(eeg_df))))\n    bars = plt.barh(y=eeg_df['eeg_sub_id'], width=50, left=eeg_df['eeg_label_offset_seconds'], color='plum')\n    \n    y_min, y_max = plt.ylim()\n    \n    for i,row in eeg_df.iterrows():\n        start_mid_range = row['eeg_label_offset_seconds'] + 50/2 - 5\n        end_mid_range = row['eeg_label_offset_seconds'] + 50/2 + 5\n        \n        ymin, ymax = (y_max - 0.4 - i)/(abs(y_min) + y_max), (y_max + 0.4 - i)/(abs(y_min) + y_max)\n        plt.axvspan(xmin=start_mid_range, xmax=end_mid_range, ymin=ymin, ymax=ymax, alpha=0.2, color='blue', label='10sec vote zone' if i == 0 else None)\n        plt.text(25 + eeg_df['eeg_label_offset_seconds'].iloc[i], i+0.05, f'{eeg_df[\"expert_consensus\"].iloc[i]}', color='white', fontweight='bold', horizontalalignment='center')\n    \n    \n    plt.gca().invert_yaxis()\n    plt.ylabel('EEG sub id')\n    plt.xlabel('Time (seconds)')\n    \n    max_offset = int(eeg_df[\"eeg_label_offset_seconds\"].max())\n    eeg_time = max_offset + 50\n                     \n    plt.title(f'EEG {eeg_id} during {eeg_time} seconds')\n    plt.legend()\n    plt.show()\n    \n    \n    # PLOT THE EEG VOTES \n    #display(eeg.head(3))\n    \n    plt.figure(figsize=(20,5))\n    plt.plot(eeg['Fp1'])\n    \n    for i,row in eeg_df.iterrows():\n        plt.axvline(x=(row['eeg_label_offset_seconds']*200),color='green', label='Start of subsample' if i == 0 else None)    \n        plt.axvline(x=((row['eeg_label_offset_seconds']+50)*200),color='red', label='End of subsample' if i == 0 else None)  \n    \n    plt.title(f'EEG - Fp1 having {eeg_time}s * 200 samples/s = {eeg_time*200} samples')\n    plt.xlim(xmin=0)\n    plt.grid()\n    plt.legend()\n    plt.show()\n    \n    \n    # PLOT THE SPECTROGRAM\n    #display(spec.head(3))\n               \n    max_spec_offset = int(eeg_df['spectrogram_label_offset_seconds'].max())\n    \n    plt.figure(figsize=(20,5))\n    plt.plot(spec['time'], spec['LL_0.59'])\n    \n    for i,row in eeg_df.iterrows():\n        plt.axvline(x=row['spectrogram_label_offset_seconds'], color='green', label='Start of subsample' if i == 0 else None)   \n        plt.axvline(x=((row['spectrogram_label_offset_seconds'])+600),color='red', label='End of subsample' if i == 0 else None)\n    \n    spec[\"time\"]\n    plt.title(f'Spectrogram - LL_0.59 during {spec[\"time\"].values[-1]} seconds')\n    plt.xlim(xmin=0)\n    plt.ylabel('Frequency (Hz)')\n    plt.xlabel('Time (seconds)')\n    plt.legend()\n    plt.grid()\n    plt.show()\n\neeg_info(2366870)","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:01:25.910823Z","iopub.execute_input":"2024-02-19T09:01:25.911120Z","iopub.status.idle":"2024-02-19T09:01:27.494708Z","shell.execute_reply.started":"2024-02-19T09:01:25.911094Z","shell.execute_reply":"2024-02-19T09:01:27.493384Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"channel_map = {0: \"LL\", 1: \"LP\", 2: \"RR\", 3: \"RP\"}\ntarget_map = {'Seizure': 0, 'LPD': 1, 'GPD': 2, 'LRDA': 3, 'GRDA': 4, 'Other': 5}\ni_target_map = {y:x for x,y in target_map.items()} # inverted target map\n\nIMG_WIDTH = 256\nIMG_HEIGHT = 128\n\nX_spec = np.zeros((len(train), IMG_HEIGHT, IMG_WIDTH, 4), dtype='float32')\ny_spec = np.zeros((len(train)), dtype='int8')\n\n\ndef plot_spectrogram(index):\n    for channel in range(4):\n        img = X_spec[index,:,:,channel]\n        plt.figure(figsize=(10, 2))\n        plt.imshow(img, aspect='auto', cmap='viridis', origin='lower')\n        plt.xlabel('Time [sec]')\n        plt.ylabel('Frequency [Hz]')\n        plt.title(f'Spectrogram {train[index].spec_id} - {channel_map[channel]} : {i_target_map[y_spec[index]]}')\n        plt.show()\n        \ndef generate_spectrograms():\n    for row in train.itertuples(): # for each row in train\n        i = row[0] # get index of the row in train\n        \n        spec_id = row.spec_id\n        spec = spectrograms.item()[spec_id]\n        \n        r = np.random.randint(row.spec_offset_min, row.spec_offset_max+1)//2\n\n        for k in range(4): # 4 different channel (LL, LP, RR, RP)\n            img = spec[r:r+300, k*100:(k+1)*100].T # get 10 random minutes of the spectrogram for each channel\n\n            # log scaling\n            img = np.clip(img, np.exp(-4), np.exp(8)) # avoid 0 for log\n            img = np.log(img)\n\n            # z-score scaling\n            ep = 1e-6\n            mean = np.nanmean(img.flatten())\n            std = np.nanstd(img.flatten())\n            img = (img - mean) / (std + ep)\n            \n            # convert nan to value 0\n            img = np.nan_to_num(img, nan=0.0)\n\n            # crop to size 256\n            img = img[:,22:-22] # 300-22-22=256\n\n            X_spec[i, 14:-14,:, k] = img # 14:-14 to put the IMG_HEIGHT (100) into 128\n            y_spec[i] = target_map[row.target]\n    \ngenerate_spectrograms()","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:01:27.496133Z","iopub.execute_input":"2024-02-19T09:01:27.496575Z","iopub.status.idle":"2024-02-19T09:02:29.013496Z","shell.execute_reply.started":"2024-02-19T09:01:27.496537Z","shell.execute_reply":"2024-02-19T09:02:29.012274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"eeg_feature_df = []\nfor row in train.itertuples():\n    eeg_id = row.eeg_id\n    eeg_df = train_df[train_df[\"eeg_id\"] == eeg_id].reset_index(drop=True)\n    eeg = pd.read_parquet(f'/kaggle/input/hms-harmful-brain-activity-classification/train_eegs/{eeg_id}.parquet')\n\n    ranges = [(int(200 * offset + 4000), int(200 * offset + 6000)) for offset in eeg_df['eeg_label_offset_seconds']]\n    filtered_eeg = pd.concat([eeg.iloc[s:e].mean().to_frame().T for s, e in ranges]).reset_index(drop=True)\n    filtered_eeg['target'] = eeg_df['expert_consensus']\n    filtered_eeg.insert(0, 'eeg_id', eeg_df['eeg_id'])\n    filtered_eeg.insert(1, 'spec_id', eeg_df['spectrogram_id'])\n\n    eeg_feature_df.append(filtered_eeg)\n        \neeg_feature_df = pd.concat(eeg_feature_df).reset_index(drop=True)\ndisplay(eeg_feature_df)","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:02:29.014997Z","iopub.execute_input":"2024-02-19T09:02:29.015402Z","iopub.status.idle":"2024-02-19T09:10:14.318296Z","shell.execute_reply.started":"2024-02-19T09:02:29.015358Z","shell.execute_reply":"2024-02-19T09:10:14.317202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"eeg_feature_df = eeg_feature_df.drop(['eeg_id', 'spec_id'], axis=1)\nle = LabelEncoder()\neeg_feature_df['target'] = le.fit_transform(eeg_feature_df['target'])\n\neeg_feature_df = eeg_feature_df.drop_duplicates()\n\ndisplay(eeg_feature_df)","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:10:14.322841Z","iopub.execute_input":"2024-02-19T09:10:14.323170Z","iopub.status.idle":"2024-02-19T09:10:14.527339Z","shell.execute_reply.started":"2024-02-19T09:10:14.323144Z","shell.execute_reply":"2024-02-19T09:10:14.526299Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rs = RobustScaler()\n\n\nX = eeg_feature_df.drop(\"target\", axis=1)\ny = eeg_feature_df[\"target\"]\n\nX_scaled = pd.DataFrame(rs.fit_transform(X), columns=X.columns)\n\nX_train, X_val, y_train, y_val = train_test_split(X_scaled, y, test_size=0.1, random_state=42)\n\nnum_classes = len(set(y))","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:10:14.528586Z","iopub.execute_input":"2024-02-19T09:10:14.528903Z","iopub.status.idle":"2024-02-19T09:10:14.655784Z","shell.execute_reply.started":"2024-02-19T09:10:14.528877Z","shell.execute_reply":"2024-02-19T09:10:14.654641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_nn_model(num_neurons=64, learning_rate=1.0e-02, act='swish', dropout=0.1):\n    model = Sequential()\n\n    \n    model.add(Dense(num_neurons, activation=act, input_dim=X_train.shape[1]))\n    \n    model.add(Dense(num_neurons, activation=act))\n    model.add(Dropout(dropout))\n    model.add(BatchNormalization())\n\n    model.add(Dense(num_neurons, activation=act))\n    model.add(Dropout(dropout))\n    model.add(BatchNormalization())\n\n    model.add(Dense(int(num_neurons//2), activation=act))\n    model.add(BatchNormalization())\n\n    model.add(Dense(int(num_neurons//4), activation=act))\n    model.add(BatchNormalization())\n\n    model.add(Dense(num_classes, activation='softmax'))\n\n    model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(lr=learning_rate), metrics=['accuracy'])\n    \n    return model\n\nmodel = create_nn_model()\n\nhistory = model.fit(X_train, y_train, epochs=100, batch_size=16, validation_split=0.2)","metadata":{"execution":{"iopub.status.busy":"2024-02-19T09:10:14.657092Z","iopub.execute_input":"2024-02-19T09:10:14.657471Z","iopub.status.idle":"2024-02-19T10:01:39.354392Z","shell.execute_reply.started":"2024-02-19T09:10:14.657435Z","shell.execute_reply":"2024-02-19T10:01:39.353508Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_egg_id = 3911565283\ntest_spec_id = 853520\n\neeg_test = pd.read_parquet(f'/kaggle/input/hms-harmful-brain-activity-classification/test_eegs/{test_egg_id}.parquet')    \nplt.figure(figsize=(20,5))\nplt.plot(eeg_test['Fp1'])\n\nspec_test = pd.read_parquet(f'/kaggle/input/hms-harmful-brain-activity-classification/test_spectrograms/{test_spec_id}.parquet')    \nplt.figure(figsize=(20,5))\nplt.plot(spec_test['time'], spec_test['LL_0.59'])","metadata":{"execution":{"iopub.status.busy":"2024-02-19T10:01:39.355786Z","iopub.execute_input":"2024-02-19T10:01:39.356094Z","iopub.status.idle":"2024-02-19T10:01:39.936306Z","shell.execute_reply.started":"2024-02-19T10:01:39.356068Z","shell.execute_reply":"2024-02-19T10:01:39.935362Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"eeg_test_denoised = denoise(eeg_test, wavelet=\"db8\")\neeg_test_denoised = eeg_test_denoised.iloc[4000:6000].mean().to_frame().T\n\neeg_test_scaled = rs.transform(eeg_test_denoised)\n\nresult = model.predict(eeg_test_scaled)\nprint(result)","metadata":{"execution":{"iopub.status.busy":"2024-02-19T10:01:39.937476Z","iopub.execute_input":"2024-02-19T10:01:39.937787Z","iopub.status.idle":"2024-02-19T10:01:40.241705Z","shell.execute_reply.started":"2024-02-19T10:01:39.937757Z","shell.execute_reply":"2024-02-19T10:01:40.240779Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission[train_votes] = result\nprint (submission)","metadata":{"execution":{"iopub.status.busy":"2024-02-19T10:01:40.242901Z","iopub.execute_input":"2024-02-19T10:01:40.243208Z","iopub.status.idle":"2024-02-19T10:01:40.253643Z","shell.execute_reply.started":"2024-02-19T10:01:40.243182Z","shell.execute_reply":"2024-02-19T10:01:40.252495Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission.info()","metadata":{"execution":{"iopub.status.busy":"2024-02-19T10:07:28.694630Z","iopub.execute_input":"2024-02-19T10:07:28.695592Z","iopub.status.idle":"2024-02-19T10:07:28.711804Z","shell.execute_reply.started":"2024-02-19T10:07:28.695559Z","shell.execute_reply":"2024-02-19T10:07:28.710686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission.to_csv('submission.csv')","metadata":{"execution":{"iopub.status.busy":"2024-02-19T10:01:40.254932Z","iopub.execute_input":"2024-02-19T10:01:40.255269Z","iopub.status.idle":"2024-02-19T10:01:40.270348Z","shell.execute_reply.started":"2024-02-19T10:01:40.255243Z","shell.execute_reply":"2024-02-19T10:01:40.269619Z"},"trusted":true},"execution_count":null,"outputs":[]}]}