Exemplo n.º 1
0
    def test_mle_fit_psycho(self):
        expected = {
            'weibull50': (np.array([0.0034045, 3.9029162,
                                    .1119576]), -334.1149693046583),
            'weibull': (np.array([0.00316341, 1.72552866,
                                  0.1032307]), -261.235178611311),
            'erf_psycho': (np.array([-9.78747259, 10.,
                                     0.15967605]), -193.0509031440323),
            'erf_psycho_2gammas':
            (np.array([-11.45463779, 9.9999999, 0.24117732,
                       0.0270835]), -147.02380025592902)
        }
        for model in self.test_data.keys():
            pars, L = psy.mle_fit_psycho(self.test_data[model],
                                         P_model=model,
                                         nfits=10)
            expected_pars, expected_L = expected[model]
            self.assertTrue(np.allclose(expected_pars, pars, atol=1e-3),
                            f'unexpected pars for {model}')
            self.assertTrue(np.isclose(expected_L, L, atol=1e-3),
                            f'unexpected likelihood for {model}')

        # Test on of the models with function pars
        params = {
            'parmin': np.array([-5., 10., 0.]),
            'parmax': np.array([5., 15., .1]),
            'parstart': np.array([0., 11., 0.1]),
            'nfits': 5
        }
        model = 'erf_psycho'
        pars, L = psy.mle_fit_psycho(self.test_data[model],
                                     P_model=model,
                                     **params)
        expected = [-5, 15, 0.1]
        self.assertTrue(np.allclose(expected, pars, rtol=.01),
                        f'unexpected pars for {model}')
        self.assertTrue(np.isclose(-195.55603, L, atol=1e-5),
                        f'unexpected likelihood for {model}')
Exemplo n.º 2
0
def fit_psychfunc(df):
    choicedat = df.groupby('signedContrast').agg({
        'trial': 'max',
        'choice2': 'mean'
    }).reset_index()
    pars, L = psy.mle_fit_psycho(
        choicedat.values.transpose(),
        P_model='erf_psycho_2gammas',
        parstart=np.array(
            [choicedat['signedContrast'].mean(), 20., 0.05, 0.05]),
        parmin=np.array([choicedat['signedContrast'].min(), 0., 0., 0.]),
        parmax=np.array([choicedat['signedContrast'].max(), 100., 1, 1]))
    df2 = {
        'bias': pars[0],
        'threshold': pars[1],
        'lapselow': pars[2],
        'lapsehigh': pars[3]
    }

    return pd.DataFrame(df2, index=[0])
#bias = -10.
#threshold = 20.
#gamma = .1

# fake experimental data given those parameters
#ratio = psychofit.erf_psycho([bias, threshold, gamma],edgeMid)

# In[10]:

cc = edgeMid  # contrasts
nn = histTact + histDCS  # number of trials at each contrast
#ntrials = 40
#nn = ntrials*np.ones((np.shape(ratio)))
pp = ratio  # proportion "rightward"
pars, L = psychofit.mle_fit_psycho(np.vstack((cc, nn, pp)), 'erf_psycho',
                                   np.array([-100, 10., 0.5]),
                                   np.array([-200., 0.1, 0.]),
                                   np.array([20., 500., 1]), 50)

plt.figure(figsize=(10, 10))
plt.plot(cc, pp, 'ko', mfc='k', markersize=15)
plt.plot(
    np.arange(-550, 150, 0.1),
    psychofit.erf_psycho(pars, np.arange(-550, 150, 0.1)),
    '-b',
    linewidth=7,
    label=' threshold = {:2.0f} \n slope = {:2.0f} \n lapse = {:.01f}'.format(
        *pars))
plt.legend()
#plt.xlim([-100,100])
plt.ylim([-0.1, 1.1])
plt.plot((0, 0), (0, 1), 'k:')
Exemplo n.º 4
0
def plot_psychometric(df, color='black', ax=None, **kwargs):
    """
    Plots psychometric data for a given DataFrame of behavioural trials
    
    If the data contains more than six different contrasts (or > three per side)
    the data are fit with an erf function.  The x-axis is percent contrast and 
    the y-axis is the proportion of 'rightward choices', i.e. trials where the 
    subject turned the wheel clockwise to threshold.
    
    Example:
        df = alf.load_behaviour('2018-09-11_1_Mouse1', r'\\server\SubjectData')
        plot_psychometric(df)
        
    Args:
        df (DataFrame): DataFrame constructed from an ALF trials object.
        ax (Axes): Axes to plot to.  If None, a new figure is created.
        
    Returns:
        ax (Axes): The plot axes
    """

    if len(df['signedContrast'].unique()) > 4:
        df2 = df.groupby(['signedContrast']).agg({
            'choice': 'count',
            'choice2': 'mean'
        }).reset_index()
        df2.rename(columns={
            "choice2": "fraction",
            "choice": "ntrials"
        },
                   inplace=True)

        pars, L = psy.mle_fit_psycho(
            df2.transpose().values,  # extract the data from the df
            P_model='erf_psycho_2gammas',
            parstart=np.array([df2['signedContrast'].mean(), 20., 0.05, 0.05]),
            parmin=np.array([df2['signedContrast'].min(), 0., 0., 0.]),
            parmax=np.array([df2['signedContrast'].max(), 100., 1, 1]))
        sns.lineplot(np.arange(-100, 100),
                     psy.erf_psycho_2gammas(pars, np.arange(-100, 100)),
                     color=color,
                     ax=ax)

    # plot datapoints on top
    sns.lineplot(x='signedContrast',
                 y='choice2',
                 err_style="bars",
                 linewidth=0,
                 linestyle='None',
                 mew=0.5,
                 marker='.',
                 ci=68,
                 data=df,
                 color=color,
                 ax=ax)

    # Reduce the clutter
    ax.set_xticks([-100, -50, 0, 50, 100])
    ax.set_xticklabels(['-100', '-50', '0', '50', '100'])
    ax.set_yticks([0, .5, 1])
    # Set the limits
    ax.set_xlim([-110, 110])
    ax.set_ylim([-0.03, 1.03])
    ax.set_xlabel('Contrast (%)')

    return ax
Exemplo n.º 5
0
    def make(self, key):

        key_psy = key.copy()

        n_trials, n_correct_trials = (behavior.TrialSet & key).fetch1(
            'n_trials', 'n_correct_trials')
        key_psy['performance'] = n_correct_trials / n_trials

        trials = behavior.TrialSet.Trial & key
        trials_rt = trials.proj(rt='trial_response_time-trial_stim_on_time')
        contrasts_left = np.unique(
            trials.fetch('trial_stim_contrast_left'))[1:]  # discard contrast 0
        contrasts_right = np.unique(trials.fetch('trial_stim_contrast_right'))[
            1:]  # discard contrast 0
        trials_no_contrast = trials & 'trial_stim_contrast_right=0' & 'trial_stim_contrast_left=0'


        n_right_trials_stim_left = [len(trials & 'trial_stim_contrast_left={}'.format(contrast) & 'trial_response_choice="CCW"') \
                                    for contrast in contrasts_left]
        n_trials_stim_left = [len(trials & 'trial_stim_contrast_left={}'.format(contrast)) \
                                    for contrast in contrasts_left]
        n_right_trials_stim_right = [len(trials & 'trial_stim_contrast_right={}'.format(contrast) & 'trial_response_choice="CCW"') \
                                    for contrast in contrasts_right]
        n_trials_stim_right = [len(trials & 'trial_stim_contrast_right={}'.format(contrast)) \
                                    for contrast in contrasts_right]

        p_right_stim_left = np.divide(n_right_trials_stim_left,
                                      n_trials_stim_left)
        p_right_stim_right = np.divide(n_right_trials_stim_right,
                                       n_trials_stim_right)

        rt_stim_left = [(trials_rt & (trials & 'trial_stim_contrast_left={}'.format(contrast))).fetch('rt').mean() \
                        for contrast in contrasts_left]
        rt_stim_right = [(trials_rt & (trials & 'trial_stim_contrast_right={}'.format(contrast))).fetch('rt').mean() \
                        for contrast in contrasts_right]

        trials_no_contrast = trials & 'trial_stim_contrast_right=0' & 'trial_stim_contrast_left=0'
        if trials_no_contrast:
            key_psy['contrasts'] = np.hstack(
                [np.negative(contrasts_left[::-1]), 0, contrasts_right]) * 100

            p_right_no_contrast = len(trials_no_contrast
                                      & 'trial_response_choice="CCW"') / len(
                                          trials_no_contrast)
            key_psy['prob_choose_right'] = np.hstack([
                p_right_stim_left[::-1], p_right_no_contrast,
                p_right_stim_right
            ])
            n_total_trials = np.hstack([
                n_trials_stim_left,
                len(trials_no_contrast), n_trials_stim_right
            ])
            rt_no_contrast = (trials_rt
                              & trials_no_contrast).fetch('rt').mean()
            key_psy['rt'] = np.hstack(
                [rt_stim_left, rt_no_contrast, rt_stim_right])
        else:
            key_psy['contrasts'] = np.hstack(
                [np.negative(contrasts_left[::-1]), contrasts_right]) * 100
            key_psy['prob_choose_right'] = np.hstack([
                (p_right_stim_left[::-1]), p_right_stim_right
            ])
            n_total_trials = np.hstack(
                [n_trials_stim_left, n_trials_stim_right])
            key_psy['rt'] = np.hstack([rt_stim_left, rt_stim_right])

        pars, L = psy.mle_fit_psycho(np.vstack([key_psy['contrasts'], n_total_trials, key_psy['prob_choose_right']]), \
                P_model='erf_psycho_2gammas', \
                parstart=np.array([key_psy['contrasts'].mean(), 20., 0.05, 0.05]), \
                parmin=np.array([key_psy['contrasts'].mean(), 0., 0., 0.]), \
                parmax=np.array([key_psy['contrasts'].mean(), 100., 1, 1]))
        print(pars)
        key_psy['bias'] = pars[0]
        key_psy['threshold'] = pars[1]
        key_psy['lapse_low'] = pars[2]
        key_psy['lapse_high'] = pars[3]

        self.insert1(key_psy)