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)
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
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
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",
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)
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
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