Beispiel #1
0
def get_nobrainer_trials(subject, bidsdir):
    """
    Return the trials where a decision is a "nobrainer", a trial where both the
    reward probability and magnitude of one option is higher than that of the
    other option.
    :param subject: str, subject identifier
    :param bidsdir: str, path to BIDS dir with logfiles
    :return:
    """
    df = read_bids_logfile(subject=subject,
                           bidsdir=bidsdir)
    # where is the both Magnitude and Probability of reward greater for one
    # option over the other? -> nobrainer trials
    right = df['trial_no'][(df.RoptMag > df.LoptMag) &
                           (df.RoptProb > df.LoptProb)].values
    left = df['trial_no'][(df.LoptMag > df.RoptMag) &
                          (df.LoptProb > df.RoptProb)].values
    # the remaining trials require information integration ('brainer' trials)
    brainer = [i for i in df['trial_no'].values
               if i not in right and i not in left]

    # brainer and no-brainer trials should add up
    assert len(brainer) + len(right) + len(left) == len(df['trial_no'].values)
    # make sure that right and left no brainers do not intersect - if they have
    # common values, something went wrong
    assert not bool(set(right) & set(left))
    # make sure to only take those no-brainer trials where participants actually
    # behaved as expected. Those trials where it would be a nobrainer to pick X,
    # but the subject chose Y, are excluded with this.
    consistent_nobrainer_left = \
        [trial for trial in left if
         df['choice'][df['trial_no'] == trial].values == 1]
    consistent_nobrainer_right = \
        [trial for trial in right if
         df['choice'][df['trial_no'] == trial].values == 2]
    logging.info(f"Subject {subject} underwent a total of {len(right)} "
                 f"no-brainer trials for right choices, and a total of "
                 f"{len(left)} no-brainer trials for left choices. The subject "
                 f"chose consistently according to the no-brainer nature of "
                 f"the trial in N={len(consistent_nobrainer_right)} cases for "
                 f"right no-brainers, and in "
                 f"N={len(consistent_nobrainer_left)} cases for left "
                 f"no-brainers.")
    # create a dictionary with brainer and no-brainer trials. We leave out all
    # no-brainer trials where the participant hasn't responded in accordance to
    # the no-brain nature of the trial
    choices = {'brainer': brainer,
               'nobrainer_left': consistent_nobrainer_left,
               'nobrainer_right': consistent_nobrainer_right}

    return choices
Beispiel #2
0
def bigdf(bidsdir):
    """
    aggregate all log files into one big dataframe
    :param bidsdir:
    :return:
    """
    # need a list of sub ids, can't think of something less convoluted atm
    subs = sorted([sub[-3:] for sub in glob(bidsdir + '/' + 'sub-*')])
    dfs = []
    for subject in subs:
        df = read_bids_logfile(subject, bidsdir)
        # add a subject identifier
        df['subject'] = subject
        dfs.append(df)
    # merge the dfs. Some subjects have more column keys than others, join=outer
    # fills them with nans where they don't exist
    return pd.concat(dfs, axis=0, join='outer')
Beispiel #3
0
def get_leftright_trials(subject,
                         bidsdir):
    """
    Return the trials where a left choice and where a right choice was made.
    Logdata coding for left and right is probably 1 = left, 2 = right (based on
    experiment file)
    :param subject: str, subject identifier, e.g., '001'
    :param bidsdir: str, Path to the root of a BIDS raw dataset
    :return: choices; dict of trial numbers belonging to left or right choices
    """
    df = read_bids_logfile(subject=subject,
                           bidsdir=bidsdir)
    # get a list of epochs in which the participants pressed left and right
    left_choice = df['trial_no'][df['choice'] == 1].values
    right_choice = df['trial_no'][df['choice'] == 2].values
    choices = {'left (1)': left_choice,
               'right (2)': right_choice}

    return choices
Beispiel #4
0
def stats_per_subject(subject, bidsdir, results=None):
    """
    Compute summary statistics for a subject
    :param subject:
    :param bidsdir:
    :return:
    """
    df = read_bids_logfile(subject, bidsdir)
    if results is None:
        results = {}
    # median reaction time over all trials
    results[subject] = {'median RT global': np.nanmedian(df['RT'])}
    results[subject] = {'mean RT global': np.nanmean(df['RT'])}
    results[subject] = {'Std RT global': np.nanstd(df['RT'])}
    # no-brainer trials
    right = df['RT'][(df.RoptMag > df.LoptMag)
                     & (df.RoptProb > df.LoptProb)].values
    left = df['RT'][(df.LoptMag > df.RoptMag)
                    & (df.LoptProb > df.RoptProb)].values
    nobrainer = np.append(right, left)
    results[subject] = {'median RT nobrainer': np.nanmedian(nobrainer)}
    results[subject] = {'mean RT nobrainer': np.nanmean(nobrainer)}
    results[subject] = {'Std RT nobrainer': np.nanstd(nobrainer)}
Beispiel #5
0
def get_decision_timespan_on_and_offsets(subject, bidsdir):
    """
    For each trial, get a time frame around the point in time that a decision
    was made.
    :param subject; str, subject identifier
    :param bidsdir: str, path to BIDS dir with log files
    :return: trials_to_rts: dict, and association of trial numbers to 800ms time
    slices around the time of decision in the given trial
    """
    logs = read_bids_logfile(subject=subject, bidsdir=bidsdir)
    trials_and_rts = logs[['trial_no', 'RT']].values
    logging.info(f'The average reaction time was '
                 f'{np.nanmean(trials_and_rts[:, 1])}')
    # mark nans with larger RTs
    logging.info('Setting nan reaction times to implausibly large values.')
    np.nan_to_num(trials_and_rts, nan=100, copy=False)
    # collect the trial numbers where reaction times are too large to fit into
    # the trial. For now, this is at 3 seconds.
    trials_to_remove = trials_and_rts[np.where(trials_and_rts[:, 1] > 3)][:, 0]
    # initialize a dict to hold all information
    trials_to_rts = {}
    for trial, rt in trials_and_rts:
        # Now, add RT to the start of the second visual stimulus to get the
        # approximate decision time from trial onset
        # (0.7s + 2.0s = 2.7s)
        decision_time = rt + 2.7
        # plausibility check, no decision is made before a decision is possible
        assert decision_time > 2.7
        # calculate the slice needed for indexing the data for the specific
        # trial. We round down so that the specific upper or lower time point
        # can be used as an index to subset the data frame
        window = [decision_time - 0.4, decision_time + 0.4]
        if trial not in trials_to_remove:
            trials_to_rts[trial] = window

    return trials_to_rts