Example #1
0
    def is_runner_better(self):
        runner_model = Model()
        with runner_model:
            self.switchpoint = DiscreteUniform('switchpoint',lower=0,upper=self.num_efforts)

            self.lvl1 = StudentT('lvl1',mu=95,lam=10**-2,nu=5)

            self.lvl2 = StudentT('lvl2',mu=95,lam=10**-2,nu=5)

            self.lvl = switch(self.switchpoint >= np.arange(self.num_efforts),self.lvl1,self.lvl2)

            self.my_runs = StudentT('runs',mu = self.lvl,lam=15**-2,nu=5,observed=self.efforts)

            startvals = find_MAP(model=runner_model)

            self.trace = sample(10000,start=startvals,njobs=5)
Example #2
0
def hmetad_groupLevel(data: dict, sample_model: bool = True, **kwargs):
    """Compute hierachical meta-d' at the subject level.

    This is an internal function. The group level model must be
    called using :py:func:`metadPy.hierarchical.hmetad`.

    Parameters
    ----------
    data : dict
        Response data.
    sample_model : boolean
        If `False`, only the model is returned without sampling.
    **kwargs : keyword arguments
        All keyword arguments are passed to `func::pymc3.sampling.sample`.

    Returns
    -------
    model : :py:class:`pymc3.Model` instance
        The pymc3 model. Encapsulates the variables and likelihood factors.
    trace : :py:class:`pymc3.backends.base.MultiTrace` or
        :py:class:`arviz.InferenceData`
        A `MultiTrace` or `ArviZ InferenceData` object that contains the
        samples.

    References
    ----------
    .. [#] Fleming, S.M. (2017) HMeta-d: hierarchical Bayesian estimation
    of metacognitive efficiency from confidence ratings, Neuroscience of
    Consciousness, 3(1) nix007, https://doi.org/10.1093/nc/nix007
    """
    nSubj = data["nSubj"]
    hits = data["hits"]
    falsealarms = data["falsealarms"]
    s = data["s"]
    n = data["n"]
    counts = data["counts"]
    nRatings = data["nRatings"]
    Tol = data["Tol"]
    cr = data["cr"]
    m = data["m"]

    with Model() as model:

        # hyperpriors on d, c and c2
        mu_c1 = Normal(
            "mu_c1", mu=0, tau=0.01, shape=(1), testval=np.random.rand() * 0.1
        )
        mu_c2 = Normal(
            "mu_c2", mu=0, tau=0.01, shape=(1, 1), testval=np.random.rand() * 0.1
        )
        mu_d1 = Normal(
            "mu_d1", mu=0, tau=0.01, shape=(1), testval=np.random.rand() * 0.1
        )

        sigma_c1 = HalfNormal(
            "sigma_c1", tau=0.01, shape=(1), testval=np.random.rand() * 0.1
        )
        sigma_c2 = HalfNormal(
            "sigma_c2", tau=0.01, shape=(1, 1), testval=np.random.rand() * 0.1
        )
        sigma_d1 = HalfNormal(
            "sigma_d1", tau=0.01, shape=(1), testval=np.random.rand() * 0.1
        )

        # Type 1 priors
        c1_tilde = Normal("c1_tilde", mu=0, sigma=1, shape=(nSubj, 1))
        c1 = Deterministic("c1", mu_c1 + sigma_c1 * c1_tilde)

        d1_tilde = Normal("d1_tilde", mu=0, sigma=1, shape=(nSubj, 1))
        d1 = Deterministic("d1", mu_d1 + sigma_d1 * d1_tilde)

        # TYPE 1 SDT BINOMIAL MODEL
        h = cumulative_normal(d1 / 2 - c1)
        f = cumulative_normal(-d1 / 2 - c1)
        H = Binomial("H", n=s, p=h, observed=hits)
        FA = Binomial("FA", n=n, p=f, observed=falsealarms)

        # Hyperpriors on mRatio
        mu_logMratio = Normal(
            "mu_logMratio", mu=0, tau=1, shape=(1), testval=np.random.rand() * 0.1
        )
        sigma_delta = HalfNormal("sigma_delta", tau=1, shape=(1))

        delta_tilde = Normal("delta_tilde", mu=0, sigma=1, shape=(nSubj, 1))
        delta = Deterministic("delta", sigma_delta * delta_tilde)

        epsilon_logMratio = Beta("epsilon_logMratio", 1, 1, shape=(1))
        logMratio = Deterministic("logMratio", mu_logMratio + epsilon_logMratio * delta)
        mRatio = Deterministic("mRatio", math.exp(logMratio))

        # Type 2 priors
        meta_d = Deterministic("meta_d", mRatio * d1)

        # Specify ordered prior on criteria
        # bounded above and below by Type 1 c1
        cS1_hn = Normal(
            "cS1_hn",
            mu=0,
            sigma=1,
            shape=(nSubj, nRatings - 1),
            testval=np.linspace(-1.5, -0.5, nRatings - 1)
            .reshape(1, nRatings - 1)
            .repeat(nSubj, axis=0),
        )
        cS1 = Deterministic("cS1", -mu_c2 + (cS1_hn * sigma_c2))

        cS2_hn = Normal(
            "cS2_hn",
            mu=0,
            sigma=1,
            shape=(nSubj, nRatings - 1),
            testval=np.linspace(0.5, 1.5, nRatings - 1)
            .reshape(1, nRatings - 1)
            .repeat(nSubj, axis=0),
        )
        cS2 = Deterministic("cS2", mu_c2 + (cS2_hn * sigma_c2))

        # Means of SDT distributions
        S2mu = meta_d / 2
        S1mu = -meta_d / 2

        # Calculate normalisation constants
        C_area_rS1 = cumulative_normal(c1 - S1mu)
        I_area_rS1 = cumulative_normal(c1 - S2mu)
        C_area_rS2 = 1 - cumulative_normal(c1 - S2mu)
        I_area_rS2 = 1 - cumulative_normal(c1 - S1mu)

        # Get nC_rS1 probs
        nC_rS1 = cumulative_normal(cS1 - S1mu) / C_area_rS1
        nC_rS1 = Deterministic(
            "nC_rS1",
            math.concatenate(
                (
                    [
                        cumulative_normal(cS1[:, 0].reshape((nSubj, 1)) - S1mu)
                        / C_area_rS1,
                        nC_rS1[:, 1:] - nC_rS1[:, :-1],
                        (
                            (
                                cumulative_normal(c1 - S1mu)
                                - cumulative_normal(
                                    cS1[:, nRatings - 2].reshape((nSubj, 1)) - S1mu
                                )
                            )
                            / C_area_rS1
                        ),
                    ]
                ),
                axis=1,
            ),
        )

        # Get nI_rS2 probs
        nI_rS2 = (1 - cumulative_normal(cS2 - S1mu)) / I_area_rS2
        nI_rS2 = Deterministic(
            "nI_rS2",
            math.concatenate(
                (
                    [
                        (
                            (1 - cumulative_normal(c1 - S1mu))
                            - (
                                1
                                - cumulative_normal(
                                    cS2[:, 0].reshape((nSubj, 1)) - S1mu
                                )
                            )
                        )
                        / I_area_rS2,
                        nI_rS2[:, :-1]
                        - (1 - cumulative_normal(cS2[:, 1:] - S1mu)) / I_area_rS2,
                        (
                            1
                            - cumulative_normal(
                                cS2[:, nRatings - 2].reshape((nSubj, 1)) - S1mu
                            )
                        )
                        / I_area_rS2,
                    ]
                ),
                axis=1,
            ),
        )

        # Get nI_rS1 probs
        nI_rS1 = (-cumulative_normal(cS1 - S2mu)) / I_area_rS1
        nI_rS1 = Deterministic(
            "nI_rS1",
            math.concatenate(
                (
                    [
                        cumulative_normal(cS1[:, 0].reshape((nSubj, 1)) - S2mu)
                        / I_area_rS1,
                        nI_rS1[:, :-1]
                        + (cumulative_normal(cS1[:, 1:] - S2mu)) / I_area_rS1,
                        (
                            cumulative_normal(c1 - S2mu)
                            - cumulative_normal(
                                cS1[:, nRatings - 2].reshape((nSubj, 1)) - S2mu
                            )
                        )
                        / I_area_rS1,
                    ]
                ),
                axis=1,
            ),
        )

        # Get nC_rS2 probs
        nC_rS2 = (1 - cumulative_normal(cS2 - S2mu)) / C_area_rS2
        nC_rS2 = Deterministic(
            "nC_rS2",
            math.concatenate(
                (
                    [
                        (
                            (1 - cumulative_normal(c1 - S2mu))
                            - (
                                1
                                - cumulative_normal(
                                    cS2[:, 0].reshape((nSubj, 1)) - S2mu
                                )
                            )
                        )
                        / C_area_rS2,
                        nC_rS2[:, :-1]
                        - ((1 - cumulative_normal(cS2[:, 1:] - S2mu)) / C_area_rS2),
                        (
                            1
                            - cumulative_normal(
                                cS2[:, nRatings - 2].reshape((nSubj, 1)) - S2mu
                            )
                        )
                        / C_area_rS2,
                    ]
                ),
                axis=1,
            ),
        )

        # Avoid underflow of probabilities
        nC_rS1 = math.switch(nC_rS1 < Tol, Tol, nC_rS1)
        nI_rS2 = math.switch(nI_rS2 < Tol, Tol, nI_rS2)
        nI_rS1 = math.switch(nI_rS1 < Tol, Tol, nI_rS1)
        nC_rS2 = math.switch(nC_rS2 < Tol, Tol, nC_rS2)

        # TYPE 2 SDT MODEL (META-D)
        # Multinomial likelihood for response counts ordered as c(nR_S1,nR_S2)
        Multinomial(
            "CR_counts",
            cr,
            nC_rS1,
            shape=(nSubj, nRatings),
            observed=counts[:, :nRatings],
        )
        Multinomial(
            "FA_counts",
            FA,
            nI_rS2,
            shape=(nSubj, nRatings),
            observed=counts[:, nRatings : nRatings * 2],
        )
        Multinomial(
            "M_counts",
            m,
            nI_rS1,
            shape=(nSubj, nRatings),
            observed=counts[:, nRatings * 2 : nRatings * 3],
        )
        Multinomial(
            "H_counts",
            H,
            nC_rS2,
            shape=(nSubj, nRatings),
            observed=counts[:, nRatings * 3 : nRatings * 4],
        )

        if sample_model is True:

            trace = sample(return_inferencedata=True, **kwargs)

            return model, trace

        else:
            return model
Example #3
0
def mcmc_changepoint(dates,
                     ratings,
                     mcmc_iter=1000,
                     discrete=0,
                     plot_result=1):
    """This function models Yelp reviews as coming from two normal distributions
    with a switch point somewhere between them. When left of the switch point then
    reviews are drawn from the first normal distribution. To the right of the
    switch point reviews are drawn from the second normal distribution. Normal
    distributions are used if the reviews have been normalized to the user's
    average rating; otherwise if analyzing in terms of 1-5 stars set discrete=1
    and the function will do the same estimation on Poisson distributions. This
    function then finds the most likely distribution for where the switchpoint is
    and the most likely parameters for the two generator distributions by using
    Metropolis-Hastings sampling and Hamiltonian Monte Carlo."""

    # dates: Array of dates when the reviews were posted
    # ratings: Array of the ratings given by each review
    # mcmc_iter: How many iterations of the MCMC to run?
    # discrete: Should I use Normal or Poisson distributions to model the ratings?
    # (i.e. are the user-averaged or 1-5 stars)
    # plot_result: Should the function output a plot?

    number_of_ratings = np.arange(0, len(ratings))

    if discrete == 0:
        with Model() as switch_model:
            switchpoint = DiscreteUniform('switchpoint',
                                          lower=0,
                                          upper=len(dates))

            before_intensity = Normal('before_intensity', mu=0, sd=1)
            after_intensity = Normal('after_intensity', mu=0, sd=1)

            intensity = switch(switchpoint >= number_of_ratings,
                               before_intensity, after_intensity)
            sigma = HalfNormal('sigma', sd=1)

            rating = Normal('rating', mu=intensity, sd=sigma, observed=ratings)

    elif discrete == 1:
        with Model() as switch_model:
            switchpoint = DiscreteUniform('switchpoint',
                                          lower=0,
                                          upper=len(dates))

            before_intensity = Exponential('before_intensity', 1)
            after_intensity = Exponential('after_intensity', 1)

            intensity = switch(switchpoint >= number_of_ratings,
                               before_intensity, after_intensity)

            rating = Poisson('rating', intensity, observed=ratings)

    with switch_model:
        trace = sample(mcmc_iter)

    if plot_result == 1:
        traceplot(trace)
        plt.show()

    switch_posterior = trace['switchpoint']
    N_MCs = switch_posterior.shape[0]

    before_intensity_posterior = trace['before_intensity']
    after_intensity_posterior = trace['after_intensity']

    expected_stars = np.zeros(len(ratings))
    for a_rating in number_of_ratings:
        where_switch = a_rating < switch_posterior
        expected_stars[a_rating] = (
            before_intensity_posterior[where_switch].sum() +
            after_intensity_posterior[~where_switch].sum()) / N_MCs

    if plot_result == 1:
        plt.plot(dates, ratings, 'o')
        plt.plot(dates, expected_stars, 'b-')
        plt.show()

    # Return the mode and it's frequency / mcmc_iter
    b_mean, b_count = scipy.stats.mode(trace['before_intensity'])
    a_mean, a_count = scipy.stats.mode(trace['after_intensity'])
    modal_switch, count = scipy.stats.mode(trace['switchpoint'])
    sigma_est, sigma_count = scipy.stats.mode(trace['sigma'])
    differential = b_mean - a_mean
    return differential, modal_switch, expected_stars, sigma_est, switch_posterior
Example #4
0
            pmc.Wald("Passenger Onboarding",
                     mu=0.5, lam=0.2)
        refueling = \
            pmc.Wald("Refueling",
                     mu=0.25, lam=0.5)
        departure_traffic_delay = \
            pmc.Wald("Departure Traffic Delay",
                     mu=0.1, lam=0.2)

        departure_time = \
            pm.Deterministic(
                "Departure Time",
                 12.0 +
                departure_traffic_delay +
                pmm.switch(
                    passenger_onboarding >= refueling,
                    passenger_onboarding,
                    refueling))

        rough_weather = \
            pmd.Bernoulli("Rough Weather",
                          p=0.35)

        flight_time = \
            pmc.Exponential("Flight Time",
                            lam=0.5 - (0.1 * rough_weather))
        arrival_traffic_delay = \
            pmc.Wald("Arrival Traffic Delay",
                     mu=0.1, lam=0.2)

        arrival_time = \
            pm.Deterministic("Arrival time",
Example #5
0
model = pm.Model()

import pymc3.distributions.continuous as pmc
import pymc3.distributions.discrete as pmd
import pymc3.math as pmm

with model:
    passenger_onboarding = pmc.Wald('Passenger Onboarding', mu=0.5, lam=0.2)
    refueling = pmc.Wald('Refueling', mu=0.25, lam=0.5)
    departure_traffic_delay = pmc.Wald('Departure Traffic Delay', mu=0.1, lam=0.2)
    
    departure_time = pm.Deterministic('Departure Time', 
                                      12.0 + departure_traffic_delay + 
                                      pmm.switch(passenger_onboarding >= refueling, 
                                                 passenger_onboarding, 
                                                 refueling))
    
    rough_weather = pmd.Bernoulli('Rough Weather', p=0.35)
    
    flight_time = pmc.Exponential('Flight Time', lam=0.5 - (0.1 * rough_weather))
    arrival_traffic_delay = pmc.Wald('Arrival Traffic Delay', mu=0.1, lam=0.2)
    
    arrival_time = pm.Deterministic('Arrival time', 
                                    departure_time + 
                                    flight_time + 
                                    arrival_traffic_delay)
nb_samples = 500
with model:
    samples = pm.sample(draws=nb_samples, random_seed=1000)
Example #6
0
def hmetad_rm1way(data: dict, sample_model: bool = True, **kwargs: int):
    """Compute hierachical meta-d' at the subject level.

    This is an internal function. The repeated measures model must be
    called using :py:func:`metadPy.hierarchical.hmetad`.

    Parameters
    ----------
    data : dict
        Response data.
    sample_model : boolean
        If `False`, only the model is returned without sampling.
    **kwargs : keyword arguments
        All keyword arguments are passed to `func::pymc3.sampling.sample`.

    Returns
    -------
    model : :py:class:`pymc3.Model` instance
        The pymc3 model. Encapsulates the variables and likelihood factors.
    trace : :py:class:`pymc3.backends.base.MultiTrace` or
        :py:class:`arviz.InferenceData`
        A `MultiTrace` or `ArviZ InferenceData` object that contains the
        samples.

    References
    ----------
    .. [#] Fleming, S.M. (2017) HMeta-d: hierarchical Bayesian estimation
    of metacognitive efficiency from confidence ratings, Neuroscience of
    Consciousness, 3(1) nix007, https://doi.org/10.1093/nc/nix007
    """
    nSubj = data["nSubj"]
    nCond = data["nCond"]
    nRatings = data["nRatings"]
    hits = data["hits"].reshape(nSubj, 2)
    falsealarms = data["falsealarms"].reshape(nSubj, 2)
    counts = data["counts"]
    Tol = data["Tol"]
    cr = data["cr"].reshape(nSubj, 2)
    m = data["m"].reshape(nSubj, 2)
    c1 = data["c1"].reshape(nSubj, 2, 1)
    d1 = data["d1"].reshape(nSubj, 2, 1)

    with Model() as model:

        #############
        # Hyperpriors
        #############
        mu_c2 = Normal("mu_c2",
                       tau=0.01,
                       shape=(1, ),
                       testval=np.random.rand() * 0.1)
        sigma_c2 = HalfNormal("sigma_c2",
                              tau=0.01,
                              shape=(1, ),
                              testval=np.random.rand() * 0.1)

        mu_D = Normal("mu_D",
                      tau=0.001,
                      shape=(1),
                      testval=np.random.rand() * 0.1)
        sigma_D = HalfNormal("sigma_D",
                             tau=0.1,
                             shape=(1),
                             testval=np.random.rand() * 0.1)

        mu_Cond1 = Normal("mu_Cond1",
                          mu=0,
                          tau=0.001,
                          shape=(1),
                          testval=np.random.rand() * 0.1)
        sigma_Cond1 = HalfNormal("sigma_Cond1",
                                 tau=0.1,
                                 shape=(1),
                                 testval=np.random.rand() * 0.1)

        #############################
        # Hyperpriors - Subject level
        #############################
        dbase_tilde = Normal(
            "dbase_tilde",
            mu=0,
            sigma=1,
            shape=(nSubj, 1, 1),
        )
        dbase = Deterministic("dbase", mu_D + sigma_D * dbase_tilde)

        Bd_Cond1_tilde = Normal(
            "Bd_Cond1_tilde",
            mu=0,
            sigma=1,
            shape=(nSubj, 1, 1),
        )

        Bd_Cond1 = Deterministic(
            "Bd_Cond1",
            mu_Cond1 + sigma_Cond1 * Bd_Cond1_tilde,
        )

        lambda_logMratio = Gamma(
            "lambda_logMratio",
            alpha=0.001,
            beta=0.001,
            shape=(nSubj, 1, 1),
        )
        sigma_logMratio = Deterministic("sigma_logMratio",
                                        1 / math.sqrt(lambda_logMratio))

        ###############################
        # Hypterprior - Condition level
        ###############################
        mu_regression = [dbase + (Bd_Cond1 * c) for c in range(nCond)]

        log_mRatio_tilde = Normal("log_mRatio_tilde",
                                  mu=0,
                                  sigma=1,
                                  shape=(nSubj, 1, 1))
        log_mRatio = Deterministic(
            "log_mRatio",
            tt.stack(mu_regression, axis=1)[:, :, :, 0] +
            tt.tile(log_mRatio_tilde,
                    (1, 2, 1)) * tt.tile(sigma_logMratio, (1, 2, 1)),
        )

        mRatio = Deterministic("mRatio", tt.exp(log_mRatio))

        # Means of SDT distributions
        metad = Deterministic("metad", mRatio * d1)
        S2mu = Deterministic("S2mu", metad / 2)
        S1mu = Deterministic("S1mu", -metad / 2)

        # TYPE 2 SDT MODEL (META-D)
        # Multinomial likelihood for response counts
        # Specify ordered prior on criteria
        # bounded above and below by Type 1 c
        cS1_hn = Normal(
            "cS1_hn",
            mu=0,
            sigma=1,
            shape=(nSubj, nCond, nRatings - 1),
            testval=np.linspace(-1.5, -0.5, nRatings - 1).reshape(
                1, 1, nRatings - 1).repeat(nSubj, axis=0).repeat(nCond,
                                                                 axis=1),
        )
        cS1 = Deterministic("cS1", -mu_c2 + (cS1_hn * sigma_c2))

        cS2_hn = Normal(
            "cS2_hn",
            mu=0,
            sigma=1,
            shape=(nSubj, nCond, nRatings - 1),
            testval=np.linspace(0.5, 1.5, nRatings - 1).reshape(
                1, 1, nRatings - 1).repeat(nSubj, axis=0).repeat(nCond,
                                                                 axis=1),
        )
        cS2 = Deterministic("cS2", mu_c2 + (cS2_hn * sigma_c2))

        # Calculate normalisation constants
        C_area_rS1 = cumulative_normal(c1 - S1mu)
        I_area_rS1 = cumulative_normal(c1 - S2mu)
        C_area_rS2 = 1 - cumulative_normal(c1 - S2mu)
        I_area_rS2 = 1 - cumulative_normal(c1 - S1mu)

        # Get nC_rS1 probs
        nC_rS1 = cumulative_normal(cS1 - S1mu) / C_area_rS1
        nC_rS1 = Deterministic(
            "nC_rS1",
            math.concatenate(
                ([
                    cumulative_normal(cS1[:, :, 0].reshape((nSubj, 2, 1)) -
                                      S1mu) / C_area_rS1,
                    nC_rS1[:, :, 1:] - nC_rS1[:, :, :-1],
                    ((cumulative_normal(c1 - S1mu) -
                      cumulative_normal(cS1[:, :, (nRatings - 2)].reshape(
                          (nSubj, 2, 1)) - S1mu)) / C_area_rS1),
                ]),
                axis=2,
            ),
        )

        # Get nI_rS2 probs
        nI_rS2 = (1 - cumulative_normal(cS2 - S1mu)) / I_area_rS2
        nI_rS2 = Deterministic(
            "nI_rS2",
            math.concatenate(
                ([
                    ((1 - cumulative_normal(c1 - S1mu)) -
                     (1 - cumulative_normal(cS2[:, :, 0].reshape(
                         (nSubj, nCond, 1)) - S1mu))) / I_area_rS2,
                    nI_rS2[:, :, :-1] -
                    (1 - cumulative_normal(cS2[:, :, 1:] - S1mu)) / I_area_rS2,
                    (1 - cumulative_normal(cS2[:, :, nRatings - 2].reshape(
                        (nSubj, nCond, 1)) - S1mu)) / I_area_rS2,
                ]),
                axis=2,
            ),
        )

        # Get nI_rS1 probs
        nI_rS1 = (-cumulative_normal(cS1 - S2mu)) / I_area_rS1
        nI_rS1 = Deterministic(
            "nI_rS1",
            math.concatenate(
                ([
                    cumulative_normal(cS1[:, :, 0].reshape((nSubj, nCond, 1)) -
                                      S2mu) / I_area_rS1,
                    nI_rS1[:, :, :-1] +
                    (cumulative_normal(cS1[:, :, 1:] - S2mu)) / I_area_rS1,
                    (cumulative_normal(c1 - S2mu) -
                     cumulative_normal(cS1[:, :, nRatings - 2].reshape(
                         (nSubj, nCond, 1)) - S2mu)) / I_area_rS1,
                ]),
                axis=2,
            ),
        )

        # Get nC_rS2 probs
        nC_rS2 = (1 - cumulative_normal(cS2 - S2mu)) / C_area_rS2
        nC_rS2 = Deterministic(
            "nC_rS2",
            math.concatenate(
                ([
                    ((1 - cumulative_normal(c1 - S2mu)) -
                     (1 - cumulative_normal(cS2[:, :, 0].reshape(
                         (nSubj, nCond, 1)) - S2mu))) / C_area_rS2,
                    nC_rS2[:, :, :-1] -
                    ((1 - cumulative_normal(cS2[:, :, 1:] - S2mu)) /
                     C_area_rS2),
                    (1 - cumulative_normal(cS2[:, :, nRatings - 2].reshape(
                        (nSubj, nCond, 1)) - S2mu)) / C_area_rS2,
                ]),
                axis=2,
            ),
        )

        # Avoid underflow of probabilities
        nC_rS1 = math.switch(nC_rS1 < Tol, Tol, nC_rS1)
        nI_rS2 = math.switch(nI_rS2 < Tol, Tol, nI_rS2)
        nI_rS1 = math.switch(nI_rS1 < Tol, Tol, nI_rS1)
        nC_rS2 = math.switch(nC_rS2 < Tol, Tol, nC_rS2)

        for c in range(nCond):
            Multinomial(
                f"CR_counts_{c}",
                n=cr[:, c],
                p=nC_rS1[:, c, :],
                observed=counts[:, c, :nRatings],
                shape=(nSubj, nRatings),
            )
            Multinomial(
                f"H_counts_{c}",
                n=hits[:, c],
                p=nC_rS2[:, c, :],
                observed=counts[:, c, nRatings * 3:nRatings * 4],
                shape=(nSubj, nRatings),
            )
            Multinomial(
                f"FA_counts_{c}",
                n=falsealarms[:, c],
                p=nI_rS2[:, c, :],
                observed=counts[:, c, nRatings:nRatings * 2],
                shape=(nSubj, nRatings),
            )
            Multinomial(
                f"M_counts_{c}",
                n=m[:, c],
                p=nI_rS1[:, c, :],
                observed=counts[:, c, nRatings * 2:nRatings * 3],
                shape=(nSubj, nRatings),
            )

        if sample_model is True:

            trace = sample(return_inferencedata=True, **kwargs)

            return model, trace

        else:
            return model
Example #7
0
def hmetad_subjectLevel(data, sample_model=True, **kwargs):
    """Hierachical Bayesian modeling of meta-d' (subject level).

    This is an internal function. The subject level model must be
    called using :py:func:`metadPy.hierarchical.hmetad`.

    Parameters
    ----------
    data : dict
        Response data.
    sample_model : boolean
        If `False`, only the model is returned without sampling.
    **kwargs : keyword arguments
        All keyword arguments are passed to `func::pymc3.sampling.sample`.

    Returns
    -------
    model : :py:class:`pymc3.Model` instance
        The pymc3 model. Encapsulates the variables and likelihood factors.
    trace : :py:class:`pymc3.backends.base.MultiTrace` or
        :py:class:`arviz.InferenceData`
        A `MultiTrace` or `ArviZ InferenceData` object that contains the
        samples.

    References
    ----------
    .. [#] Fleming, S.M. (2017) HMeta-d: hierarchical Bayesian estimation
    of metacognitive efficiency from confidence ratings, Neuroscience of
    Consciousness, 3(1) nix007, https://doi.org/10.1093/nc/nix007
    """
    nRatings = data["nratings"]
    with Model() as model:

        # Type 1 priors
        c1 = Normal("c1", mu=0.0, tau=2)
        d1 = Normal("d1", mu=0.0, tau=0.5)

        # TYPE 1 SDT BINOMIAL MODEL
        h = cumulative_normal(d1 / 2 - c1)
        f = cumulative_normal(-d1 / 2 - c1)
        H = Binomial("H", data["S"], h, observed=data["H"])
        FA = Binomial("FA", data["N"], f, observed=data["FA"])

        # Type 2 priors
        meta_d = Normal("metad", mu=d1, tau=2)

        # Specify ordered prior on criteria
        # bounded above and below by Type 1 c1
        cS1_hn = HalfNormal(
            "cS1_hn",
            tau=2,
            shape=nRatings - 1,
            testval=np.linspace(1.5, 0.5, nRatings - 1),
        )
        cS1 = Deterministic("cS1", -cS1_hn + (c1 - data["Tol"]))

        cS2_hn = HalfNormal(
            "cS2_hn",
            tau=2,
            shape=nRatings - 1,
            testval=np.linspace(0.5, 1.5, nRatings - 1),
        )
        cS2 = Deterministic("cS2", cS2_hn + (c1 - data["Tol"]))

        # Means of SDT distributions
        S2mu = math.flatten(meta_d / 2, 1)
        S1mu = math.flatten(-meta_d / 2, 1)

        # Calculate normalisation constants
        C_area_rS1 = cumulative_normal(c1 - S1mu)
        I_area_rS1 = cumulative_normal(c1 - S2mu)
        C_area_rS2 = 1 - cumulative_normal(c1 - S2mu)
        I_area_rS2 = 1 - cumulative_normal(c1 - S1mu)

        # Get nC_rS1 probs
        nC_rS1 = cumulative_normal(cS1 - S1mu) / C_area_rS1
        nC_rS1 = Deterministic(
            "nC_rS1",
            math.concatenate(
                (
                    [
                        cumulative_normal(cS1[0] - S1mu) / C_area_rS1,
                        nC_rS1[1:] - nC_rS1[:-1],
                        (
                            (
                                cumulative_normal(c1 - S1mu)
                                - cumulative_normal(cS1[(nRatings - 2)] - S1mu)
                            )
                            / C_area_rS1
                        ),
                    ]
                ),
                axis=0,
            ),
        )

        # Get nI_rS2 probs
        nI_rS2 = (1 - cumulative_normal(cS2 - S1mu)) / I_area_rS2
        nI_rS2 = Deterministic(
            "nI_rS2",
            math.concatenate(
                (
                    [
                        (
                            (1 - cumulative_normal(c1 - S1mu))
                            - (1 - cumulative_normal(cS2[0] - S1mu))
                        )
                        / I_area_rS2,
                        nI_rS2[:-1]
                        - (1 - cumulative_normal(cS2[1:] - S1mu)) / I_area_rS2,
                        (1 - cumulative_normal(cS2[nRatings - 2] - S1mu)) / I_area_rS2,
                    ]
                ),
                axis=0,
            ),
        )

        # Get nI_rS1 probs
        nI_rS1 = (-cumulative_normal(cS1 - S2mu)) / I_area_rS1
        nI_rS1 = Deterministic(
            "nI_rS1",
            math.concatenate(
                (
                    [
                        cumulative_normal(cS1[0] - S2mu) / I_area_rS1,
                        nI_rS1[:-1] + (cumulative_normal(cS1[1:] - S2mu)) / I_area_rS1,
                        (
                            cumulative_normal(c1 - S2mu)
                            - cumulative_normal(cS1[(nRatings - 2)] - S2mu)
                        )
                        / I_area_rS1,
                    ]
                ),
                axis=0,
            ),
        )

        # Get nC_rS2 probs
        nC_rS2 = (1 - cumulative_normal(cS2 - S2mu)) / C_area_rS2
        nC_rS2 = Deterministic(
            "nC_rS2",
            math.concatenate(
                (
                    [
                        (
                            (1 - cumulative_normal(c1 - S2mu))
                            - (1 - cumulative_normal(cS2[0] - S2mu))
                        )
                        / C_area_rS2,
                        nC_rS2[:-1]
                        - ((1 - cumulative_normal(cS2[1:] - S2mu)) / C_area_rS2),
                        (1 - cumulative_normal(cS2[nRatings - 2] - S2mu)) / C_area_rS2,
                    ]
                ),
                axis=0,
            ),
        )

        # Avoid underflow of probabilities
        nC_rS1 = math.switch(nC_rS1 < data["Tol"], data["Tol"], nC_rS1)
        nI_rS2 = math.switch(nI_rS2 < data["Tol"], data["Tol"], nI_rS2)
        nI_rS1 = math.switch(nI_rS1 < data["Tol"], data["Tol"], nI_rS1)
        nC_rS2 = math.switch(nC_rS2 < data["Tol"], data["Tol"], nC_rS2)

        # TYPE 2 SDT MODEL (META-D)
        # Multinomial likelihood for response counts ordered as c(nR_S1,nR_S2)
        Multinomial(
            "CR_counts",
            data["CR"],
            nC_rS1,
            shape=nRatings,
            observed=data["counts"][:nRatings],
        )
        Multinomial(
            "FA_counts",
            FA,
            nI_rS2,
            shape=nRatings,
            observed=data["counts"][nRatings : nRatings * 2],
        )
        Multinomial(
            "M_counts",
            data["M"],
            nI_rS1,
            shape=nRatings,
            observed=data["counts"][nRatings * 2 : nRatings * 3],
        )
        Multinomial(
            "H_counts",
            H,
            nC_rS2,
            shape=nRatings,
            observed=data["counts"][nRatings * 3 : nRatings * 4],
        )

        if sample_model is True:
            trace = sample(
                trace=[meta_d, cS1, cS2], return_inferencedata=True, **kwargs
            )

            return model, trace

        else:
            return model