197 lines
12 KiB
(Stored with Git Annex)
Python
197 lines
12 KiB
(Stored with Git Annex)
Python
'''
|
|
Purpose
|
|
How to Run
|
|
Marisa Lytle
|
|
Feb 2020
|
|
'''
|
|
|
|
import pandas as pd
|
|
import numpy as np
|
|
|
|
def deidentify(data,info):
|
|
|
|
#Read in birthdate data
|
|
bday_file = "./Birthdates.csv"
|
|
birthdates = pd.read_csv(bday_file)
|
|
birthdates['birthdate'] = pd.to_datetime(birthdates['birthdate'], format="%m/%d/%Y")
|
|
|
|
#Convert session date to datetime object
|
|
data['SessionDate2'] = pd.to_datetime(data['SessionDate'], format="%m-%d-%Y")
|
|
|
|
#Merge in birthdates
|
|
data = pd.merge(data, birthdates, on='subject', how='left')
|
|
|
|
#Calculate age in days
|
|
data['age'] = data['SessionDate2'] - data['birthdate']
|
|
data['age'] = data['age'].dt.days
|
|
|
|
data['ShiftedSessionDate'] = data['SessionDate2'] + pd.DateOffset(days=info['shift']) - pd.DateOffset(years=200)
|
|
|
|
data = data.drop(['SessionDate','SessionDate2', 'birthdate', 'Clock.Information', 'SessionStartDateTimeUtc'], axis=1)
|
|
|
|
return data
|
|
|
|
def onset_calc(run_data):
|
|
|
|
#Calculate average onsets to use for subjects that cannot be calculated due to missing task or trial onsets
|
|
if run_data['task_onset'].isnull().values.any() or run_data['trial_onset'].isnull().values.any():
|
|
run_data['onset'] = 0
|
|
elif run_data['task_onset'].notnull().values.any() and run_data['trial_onset'].notnull().values.any():
|
|
run_data['onset'] = (run_data['trial_onset'] - run_data['task_onset']).round(4)
|
|
|
|
return run_data
|
|
|
|
def clean_col(data):
|
|
if 'Present.OnsetTime' not in data.columns:
|
|
data = data.rename(columns={"Present.RESP": "window1_response", "Present.RT": "window1_RT",
|
|
"Response.RESP": "window2_response", "Response.RT": "window2_RT", "SoundFile": "stim_file",
|
|
"Condition": "trial_type", "Subject": "subject", "Response.Duration": "window2_dur", "Correct": "correct"})
|
|
data['task_onset1'] = 0
|
|
data['task_onset2'] = 0
|
|
data['trial_onset'] = 0
|
|
elif 'Blank.OnsetTime' not in data.columns:
|
|
data = data.rename(columns={"Blank1.OnsetTime": "task_onset2",
|
|
"Present.OnsetTime": "trial_onset", "Present.RESP": "window1_response", "Present.RT": "window1_RT",
|
|
"Response.RESP": "window2_response", "Response.RT": "window2_RT", "SoundFile": "stim_file",
|
|
"Condition": "trial_type", "Subject": "subject", "Response.Duration": "window2_dur", "Correct": "correct"})
|
|
data['task_onset1'] = 0
|
|
elif 'Blank1.OnsetTime' not in data.columns:
|
|
data = data.rename(columns={"Blank.OnsetTime": "task_onset1",
|
|
"Present.OnsetTime": "trial_onset", "Present.RESP": "window1_response", "Present.RT": "window1_RT",
|
|
"Response.RESP": "window2_response", "Response.RT": "window2_RT", "SoundFile": "stim_file",
|
|
"Condition": "trial_type", "Subject": "subject", "Response.Duration": "window2_dur", "Correct": "correct"})
|
|
data['task_onset2'] = 0
|
|
|
|
else:
|
|
data = data.rename(columns={"Blank.OnsetTime": "task_onset1","Blank1.OnsetTime": "task_onset2",
|
|
"Present.OnsetTime": "trial_onset", "Present.RESP": "window1_response", "Present.RT": "window1_RT",
|
|
"Response.RESP": "window2_response", "Response.RT": "window2_RT", "SoundFile": "stim_file",
|
|
"Condition": "trial_type", "Subject": "subject", "Response.Duration": "window2_dur", "Correct": "correct"})
|
|
|
|
#initialize task onset column
|
|
data['task_onset'] = 0
|
|
|
|
#merge the two different task onset columns together as Gram1 uses task_onset1 and others use task_onset2
|
|
for x in range(len(data['subject'].values)):
|
|
if data['task_onset1'].iloc[x] > 0:
|
|
data.loc[x,'task_onset'] = data['task_onset1'].iloc[x]
|
|
elif data['task_onset2'].iloc[x] > 0:
|
|
data.loc[x,'task_onset'] = data['task_onset2'].iloc[x]
|
|
else:
|
|
data.loc[x,'task_onset'] = np.nan
|
|
|
|
#Convert ms to sec
|
|
data[['task_onset', 'trial_onset', 'window1_RT', 'window2_RT', 'window2_dur']] \
|
|
= data[['task_onset', 'trial_onset', 'window1_RT', 'window2_RT', 'window2_dur']].applymap(lambda x: x / 1000)
|
|
|
|
#Take off extra characters from Experiment name and stimulus names
|
|
data['ExperimentName'] = data['ExperimentName'].map(lambda x: x.lstrip('9_'))
|
|
data['ExperimentName'] = data['ExperimentName'].map(lambda x: x.rstrip('_font'))
|
|
data['ExperimentName'] = data['ExperimentName'].map(lambda x: x.rstrip('_onsets'))
|
|
data['ExperimentName'] = data['ExperimentName'].map(lambda x: x.rstrip('_test'))
|
|
data['ExperimentName'] = data['ExperimentName'].map(lambda x: x.rstrip(' - Final'))
|
|
data['ExperimentName'] = data['ExperimentName'].map(lambda x: x.rstrip('_gray'))
|
|
data['stim_file'] = data['stim_file'].map(lambda x: x.lstrip('Stimuli/'))
|
|
|
|
data['window1_response_raw'] = data['window1_response']
|
|
|
|
#correct reaction times listed as 0 to nan for non responses
|
|
for x in range(len(data['window1_RT'].values)):
|
|
if np.isnan(data['window1_response'].iloc[x]):
|
|
data.loc[x,'window1_RT'] = np.nan
|
|
if np.isnan(data['window2_response'].iloc[x]):
|
|
data.loc[x,'window2_RT'] = np.nan
|
|
if np.isnan(data['window1_RT'].iloc[x]):
|
|
data.loc[x,'window1_response'] = np.nan
|
|
|
|
return data
|
|
|
|
|
|
def calc_rt_acc(run_data):
|
|
control_trials = ['G_GC', 'P_SC', 'SP_Co', 'S_SC']
|
|
#Initialize calculated columns
|
|
run_data['calculated_response'] = 0
|
|
run_data['calculated_RT'] = 0
|
|
run_data['calculated_accuracy'] = 0
|
|
|
|
run_data['duration'] = run_data["window2_dur"] + 1.75
|
|
|
|
#Do the RT and ACC calculations following rules listed in ELP_TaskAccRT.docx
|
|
for trial in range(len(run_data['subject'].values)):
|
|
|
|
if trial == (len(run_data['subject'].values)-1):
|
|
if pd.notnull(run_data['window2_response'].iloc[trial]) and run_data['window2_RT'].iloc[trial] > 0.25:
|
|
run_data.loc[trial,'calculated_response'] = run_data['window2_response'].iloc[trial]
|
|
run_data.loc[trial,'calculated_RT'] = run_data['window2_RT'].iloc[trial] + 0.75
|
|
elif pd.isnull(run_data['window2_response'].iloc[trial]) or run_data['window2_RT'].iloc[trial] < 0.25:
|
|
run_data.loc[trial,'calculated_response'] = np.nan
|
|
run_data.loc[trial,'calculated_RT'] = np.nan
|
|
|
|
elif run_data['trial_type'].iloc[trial] not in control_trials:
|
|
if pd.notnull(run_data['window2_response'].iloc[trial]) and run_data['window2_RT'].iloc[trial] > 0.25 :
|
|
run_data.loc[trial,'calculated_response'] = run_data['window2_response'].iloc[trial]
|
|
run_data.loc[trial,'calculated_RT'] = run_data['window2_RT'].iloc[trial] + 0.75
|
|
elif (pd.isnull(run_data['window2_response'].iloc[trial]) or run_data['window2_RT'].iloc[trial] < 0.25) \
|
|
and (run_data['trial_type'].iloc[trial+1] in control_trials):
|
|
run_data.loc[trial,'calculated_response'] = np.nan
|
|
run_data.loc[trial,'calculated_RT'] = np.nan
|
|
elif (pd.isnull(run_data['window2_response'].iloc[trial]) or run_data['window2_RT'].iloc[trial] < 0.25)\
|
|
and (run_data['trial_type'].iloc[trial+1] not in control_trials) and pd.notnull(run_data['window1_response'].iloc[trial+1]):
|
|
run_data.loc[trial,'calculated_response'] = run_data['window1_response'].iloc[trial+1]
|
|
run_data.loc[trial,'calculated_RT'] = run_data['window1_RT'].iloc[trial+1] + run_data['duration'].iloc[trial]
|
|
elif (pd.isnull(run_data['window2_response'].iloc[trial]) or run_data['window2_RT'].iloc[trial] < 0.25)\
|
|
and (run_data['trial_type'].iloc[trial+1] not in control_trials) and pd.isnull(run_data['window1_response'].iloc[trial+1])\
|
|
and run_data['window2_RT'].iloc[trial+1] < 0.25 and pd.notnull(run_data['window2_response'].iloc[trial+1]):
|
|
run_data.loc[trial,'calculated_response'] = run_data['window2_response'].iloc[trial+1]
|
|
run_data.loc[trial,'calculated_RT'] = run_data['duration'].iloc[trial] + 0.75 + run_data['window2_RT'].iloc[trial+1]
|
|
else:
|
|
run_data.loc[trial,'calculated_response'] = np.nan
|
|
run_data.loc[trial,'calculated_RT'] = np.nan
|
|
|
|
elif run_data['trial_type'].iloc[trial] in control_trials:
|
|
if pd.notnull(run_data['window2_response'].iloc[trial]):
|
|
run_data.loc[trial,'calculated_response'] = run_data['window2_response'].iloc[trial]
|
|
run_data.loc[trial,'calculated_RT'] = run_data['window2_RT'].iloc[trial] + 0.75
|
|
elif pd.isnull(run_data['window2_response'].iloc[trial]) and pd.notnull(run_data['window1_response'].iloc[trial]):
|
|
run_data.loc[trial,'calculated_response'] = run_data['window1_response'].iloc[trial]
|
|
run_data.loc[trial,'calculated_RT'] = run_data['window1_RT'].iloc[trial]
|
|
elif run_data['trial_type'].iloc[trial+1] in control_trials:
|
|
run_data.loc[trial,'calculated_response'] = np.nan
|
|
run_data.loc[trial,'calculated_RT'] = np.nan
|
|
elif pd.isnull(run_data['window2_response'].iloc[trial]) \
|
|
and (run_data['trial_type'].iloc[trial+1] not in control_trials) and (pd.notnull(run_data['window1_response'].iloc[trial+1])):
|
|
run_data.loc[trial,'calculated_response'] = run_data['window1_response'].iloc[trial+1]
|
|
run_data.loc[trial,'calculated_RT'] = run_data['window1_RT'].iloc[trial+1] + run_data['duration'].iloc[trial]
|
|
elif pd.isnull(run_data['window2_response'].iloc[trial]) \
|
|
and (run_data['trial_type'].iloc[trial+1] not in control_trials) and (pd.isnull(run_data['window1_response'].iloc[trial+1]))\
|
|
and (run_data['window2_RT'].iloc[trial+1] < 0.25 and pd.notnull(run_data['window2_response'].iloc[trial+1])):
|
|
run_data.loc[trial,'calculated_response'] = run_data['window2_response'].iloc[trial+1]
|
|
run_data.loc[trial,'calculated_RT'] = run_data['duration'].iloc[trial] + 0.75 + run_data['window2_RT'].iloc[trial+1]
|
|
else:
|
|
run_data.loc[trial,'calculated_response'] = np.nan
|
|
run_data.loc[trial,'calculated_RT'] = np.nan
|
|
|
|
#Determine if calculated response is correct and save to calculated_accuracy column
|
|
for ans in range(len(run_data['correct'].values)):
|
|
if run_data['correct'].iloc[ans] == run_data['calculated_response'].iloc[ans]:
|
|
run_data.loc[ans,'calculated_accuracy'] = 1
|
|
elif run_data['correct'].iloc[ans] != run_data['calculated_response'].iloc[ans]:
|
|
run_data.loc[ans,'calculated_accuracy'] = 0
|
|
|
|
#Calculate accuracy, RT, and duration column
|
|
run_data['duration'] = run_data['duration'].round(4)
|
|
#all nan data to 'n/a'
|
|
run_data['calculated_RT'] = run_data['calculated_RT'].round(4)
|
|
|
|
for col in list(run_data):
|
|
run_data[col] = run_data[col].replace(np.nan, 'n/a')
|
|
|
|
run_data['window1_response'] = run_data['window1_response_raw']
|
|
|
|
run_data = run_data.drop(['unique_time'], axis=1)
|
|
|
|
events = run_data[['onset', 'duration', 'trial_type', 'correct', 'window1_response', 'window1_RT', 'window2_response', 'window2_RT', 'stim_file', 'calculated_accuracy',
|
|
'calculated_RT']]
|
|
|
|
return run_data, events
|
|
|