From cf339483c9e66f589e19a059e96ad08e76520e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toomas=20Erik=20Anij=C3=A4rv?= Date: Tue, 30 May 2023 09:21:29 +1000 Subject: [PATCH] SART behavioural measures extraction - find all the correct GO and incorrect NO-GO events and calculate the response times via button press - calculate descriptives for the response times and export --- templates/sart/sart_erp_preprocessing.ipynb | 110 ++++++++++++-------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/templates/sart/sart_erp_preprocessing.ipynb b/templates/sart/sart_erp_preprocessing.ipynb index 84d43be..eb9e5bd 100644 --- a/templates/sart/sart_erp_preprocessing.ipynb +++ b/templates/sart/sart_erp_preprocessing.ipynb @@ -75,7 +75,8 @@ "\n", "# Event names with IDs for GO and NO-GO trials\n", "event_dict = {'GO trial': 4,\n", - " 'NO-GO trial': 8}\n", + " 'NO-GO trial': 8,\n", + " 'Button press': 16}\n", "\n", "# Button press ID\n", "button_id = 16" @@ -132,43 +133,90 @@ " .set_eeg_reference(ref_channels='average', verbose=False)\n", " \n", " # Filter the signal with bandpass filter and remove EOG artefacts with SSP\n", - " filt = prep.filter_raw_data(raw,filter_design, line_remove=None, eog_channels=eog_channels,\n", + " filt = prep.filter_raw_data(raw, filter_design, line_remove=None, eog_channels=eog_channels,\n", " plot_filt=False, savefig=False, verbose=False)\n", " \n", " # Find events from the filtered EEG data and name them\n", " events = mne.find_events(filt, stim_channel=stimulus_channel, consecutive=False, output='onset')\n", " \n", " # Create an array and dataframe of successful GO (followed with button press) and NO-GO trials (no button press)\n", - " success_go_nogo_events = []\n", + " success_events_total = []\n", + " success_go = []\n", + " unsuccess_nogo = []\n", " df_success_temp = pd.DataFrame(index=[subject_names[i]],\n", " data={'Total GO' : np.sum(events[:, 2] == event_dict['GO trial']),\n", " 'Total NO-GO' : np.sum(events[:, 2] == event_dict['NO-GO trial']),\n", - " 'Correct GO': 0, 'Correct NO-GO': 0})\n", + " 'Correct GO': 0, 'Correct NO-GO': 0,\n", + " 'Incorrect GO': 0, 'Incorrect NO-GO': 0})\n", + " # Go through all events to check if they were successful or not\n", " for m in range(len(events)):\n", - " if events[m][2] == event_dict['GO trial'] and events[m+1][2] == button_id:\n", - " success_go_nogo_events.append(events[m])\n", - " df_success_temp['Correct GO'] += 1\n", - " if events[m][2] == event_dict['NO-GO trial'] and events[m+1][2] != button_id:\n", - " success_go_nogo_events.append(events[m])\n", - " df_success_temp['Correct NO-GO'] += 1\n", - " success_go_nogo_events = np.asarray(success_go_nogo_events)\n", - " df_success_temp['Incorrect GO'] = df_success_temp['Total GO'] - df_success_temp['Correct GO']\n", - " df_success_temp['Incorrect NO-GO'] = df_success_temp['Total NO-GO'] - df_success_temp['Correct NO-GO']\n", + " # If event is a GO, check for button press\n", + " if events[m][2] == event_dict['GO trial']:\n", + " if events[m+1][2] == button_id:\n", + " # If there is a button press -> success\n", + " success_events_total.append(events[m])\n", + " success_events_total.append(events[m+1])\n", + " success_go.append(events[m])\n", + " success_go.append(events[m+1])\n", + " df_success_temp['Correct GO'] += 1\n", + " else:\n", + " # If there is no button press -> fail\n", + " df_success_temp['Incorrect GO'] += 1\n", + " # If event is a NO-GO, check for no button press\n", + " if events[m][2] == event_dict['NO-GO trial']:\n", + " if events[m+1][2] != button_id:\n", + " # If there is no button press -> success\n", + " success_events_total.append(events[m])\n", + " df_success_temp['Correct NO-GO'] += 1\n", + " else:\n", + " # If there is a button press -> fail\n", + " unsuccess_nogo.append(events[m])\n", + " unsuccess_nogo.append(events[m+1])\n", + " df_success_temp['Incorrect NO-GO'] += 1\n", + " success_events_total = np.asarray(success_events_total)\n", + " success_go = np.asarray(success_go)\n", + " unsuccess_nogo = np.asarray(unsuccess_nogo)\n", + "\n", + " # Calculate response times to button press for correct GO and incorrect NO-GO\n", + " if len(success_go)!=0:\n", + " rt_go = np.diff(success_go[:, 0])[0::2]/raw.info['sfreq']\n", + " else:\n", + " rt_go = 0\n", + " if len(unsuccess_nogo)!=0:\n", + " rt_nogo = np.diff(unsuccess_nogo[:, 0])[0::2]/raw.info['sfreq']\n", + " else:\n", + " rt_nogo = 0\n", + "\n", + " # Calculate descriptives for these response times\n", + " df_success_temp['Average RT (Correct GO)'] = np.mean(rt_go)\n", + " df_success_temp['Average RT (Incorrect NO-GO)'] = np.mean(rt_nogo)\n", + " df_success_temp['SD RT (Correct GO)'] = np.std(rt_go)\n", + " df_success_temp['SD RT (Incorrect NO-GO)'] = np.std(rt_nogo)\n", + " df_success_temp['Median RT (Correct GO)'] = np.median(rt_go)\n", + " df_success_temp['Median RT (Incorrect NO-GO)'] = np.median(rt_nogo)\n", + " df_success_temp['Minimum RT (Correct GO)'] = np.min(rt_go)\n", + " df_success_temp['Minimum RT (Incorrect NO-GO)'] = np.min(rt_nogo)\n", + " df_success_temp['Maximum RT (Correct GO)'] = np.max(rt_go)\n", + " df_success_temp['Maximum RT (Incorrect NO-GO)'] = np.max(rt_nogo)\n", + " df_success_temp['RTs (Correct GO)'] = str(rt_go)\n", + " df_success_temp['RTs (Incorrect NO-GO)'] = str(rt_nogo)\n", + "\n", + " # Merge the participant dataframe with the master dataframe\n", " df_success = pd.concat([df_success, df_success_temp])\n", - " \n", + "\n", " # Plot all the events\n", " %matplotlib inline\n", " fig, axs = plt.subplots(1, 1, figsize=(10, 5))\n", - " fig = mne.viz.plot_events(success_go_nogo_events, sfreq=filt.info['sfreq'],\n", + " fig = mne.viz.plot_events(success_events_total, sfreq=filt.info['sfreq'],\n", " first_samp=filt.first_samp, event_id=event_dict,\n", " axes=axs, show=False)\n", " fig.subplots_adjust(right=0.7)\n", " axs.set_title('Successful events ({})'.format(subject_names[i]))\n", " plt.show()\n", "\n", - " # Create epochs time-locked to successful GO and NO-GO events\n", + " # Create epochs time-locked to successful GO and NO-GO events (without including the button press events)\n", " picks = mne.pick_types(filt.info, eeg=True, stim=False)\n", - " epochs = mne.Epochs(filt, success_go_nogo_events, event_id=event_dict,\n", + " epochs = mne.Epochs(filt, success_events_total[success_events_total[:, 2] != 16], event_id=event_dict,\n", " tmin=tminmax[0], tmax=tminmax[1], baseline=baseline_correction,\n", " picks=picks, preload=True)\n", " \n", @@ -207,34 +255,6 @@ "# Save the dataframe for task performance\n", "df_success.to_excel('{}/{}/{}_task_performance.xlsx'.format(results_folder,exp_folder,exp_condition))" ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Difference between unique events (just for checking)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "df_gotrials = pd.DataFrame(events[events[:,2]==4][:,0]/epochs.info['sfreq'])\n", - "df_gotrials['Event'] = 'GO'\n", - "df_nogotrials = pd.DataFrame(events[events[:,2]==8][:,0]/epochs.info['sfreq'])\n", - "df_nogotrials['Event'] = 'NO-GO'\n", - "\n", - "df_trials = pd.concat([df_gotrials, df_nogotrials]).sort_values(by=0).reset_index(drop=True)\n", - "df_trials = df_trials.rename(columns={0: 'Timepoint'})\n", - "\n", - "df_trials['Difference'] = df_trials['Timepoint'].diff()\n", - "\n", - "df_trials.describe()" - ] } ], "metadata": {