API Reference
stdpy — Python measures
The stdpy sub-module is a full NumPy/SciPy implementation of every measure.
Entry point
compute_all_measures(stim, resp, conf, n_ratings, *, matlab_compat=False, return_type='array')
Compute all 26 meta-signal measures mimicking the MATLAB output.
Returns 26 values corresponding to (see MEASURE_NAMES for the exact,
ordered list):
[
1: meta_d, 2: AUC2, 3: gamma, 4: phi, 5: deltaConf,
6: M_ratio, 7: AUC2_ratio, 8: gamma_ratio, 9: phi_ratio, 10: deltaConf_ratio,
11: M_diff, 12: AUC2_diff, 13: gamma_diff, 14: phi_diff, 15: deltaConf_diff,
16: metaNoise, 17: metaUncertainty, 18: dprime, 19: c, 20: mean_conf,
21: logL, 22: AIC, 23: BIC, 24: AICc, 25: k, 26: n
]
matlab_compat
Forwarded to fit_meta_d_mle / compute_meta_uncertainty for
single-start / high-budget MATLAB-like optimizer behaviour.
return_type :
'array' (default) — numpy.ndarray of 26 values, positional
(backward compatible).
'dict' — {measure_name: value}.
'dataframe' — single-row pandas.DataFrame with measure names
as columns.
Source code in src/metasignal/stdpy/compute_all.py
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | |
Signal Detection Theory
compute_sdt_resp(stimulus, response)
Compute SDT parameters (d', c, ln_beta).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stimulus
|
ndarray
|
Vector of 2 values (lower is noise, higher is stimulus). |
required |
response
|
ndarray
|
Vector with the same values as stimulus. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
tuple[float, float, float]
|
(dprime, c, ln_beta) |
Source code in src/metasignal/stdpy/core.py
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | |
trials_to_counts(stim_id, response, rating, n_ratings)
Convert trial data to response counts for each stimulus category.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stim_id
|
ndarray
|
0=S1, 1=S2. |
required |
response
|
ndarray
|
0=S1, 1=S2. |
required |
rating
|
ndarray
|
1 to n_ratings. |
required |
n_ratings
|
int
|
Total number of ratings. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
tuple[ndarray, ndarray]
|
(nr_s1, nr_s2) |
Source code in src/metasignal/stdpy/core.py
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | |
Meta-d' (MLE)
fit_meta_d_mle(nr_s1, nr_s2, s=1.0, *, matlab_compat=False)
Fit meta-d' using Maximum Likelihood Estimation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
nr_s1
|
ndarray
|
Counts for S1 stimulus. |
required |
nr_s2
|
ndarray
|
Counts for S2 stimulus. |
required |
s
|
float
|
Ratio of standard deviations (sd(S1)/sd(S2)). Default is 1.0. |
1.0
|
matlab_compat
|
bool
|
If True, use MATLAB |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
dict |
dict[str, Any]
|
Results of the fit. |
Source code in src/metasignal/stdpy/metad.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
Type-2 measures
compute_type2_auc(nr_s1, nr_s2)
Compute Type-2 AUC from counts.
Source code in src/metasignal/stdpy/type2.py
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | |
compute_gamma(nr_s1, nr_s2)
Compute Goodman-Kruskal's gamma.
Source code in src/metasignal/stdpy/type2.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | |
compute_phi(nr_s1, nr_s2)
Compute Phi coefficient (correlation between correctness and confidence).
Source code in src/metasignal/stdpy/type2.py
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | |
compute_delta_conf(nr_s1, nr_s2)
Compute Delta Confidence and related expected measures.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
nr_s1
|
ndarray
|
Counts array for S1 stimulus responses |
required |
nr_s2
|
ndarray
|
Counts array for S2 stimulus responses |
required |
Returns:
| Type | Description |
|---|---|
dict[str, float]
|
Dictionary containing delta_conf, delta_conf_ratio, and delta_conf_diff. |
Source code in src/metasignal/stdpy/type2.py
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | |
sdt_expect_conf(nr_s1, nr_s2)
Compute SDT-expected rating distributions (MATLAB SDTexpectConf).
Returns proportions for nR_S1_exp / nR_S2_exp (each sums to 1),
matching MATLAB nR_*_SDTexpect. Using counts instead of proportions
changes Ratio/Diff measures whenever S1 and S2 base rates differ (e.g. Locke).
Source code in src/metasignal/stdpy/type2.py
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | |
Noise and uncertainty
compute_meta_noise(stim, resp, conf, n_ratings)
Fit Lognormal Meta Noise model (MATLAB-parity search).
Source code in src/metasignal/stdpy/metanoise.py
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 | |
compute_meta_uncertainty(stim, resp, conf, n_ratings, rng=None, n_starts=5, *, matlab_compat=False)
Estimate meta-uncertainty (MATLAB compute_metaUncertainty).
Parameters
rng :
Optional generator. Used for an extra start in multi-start mode, or
as the sole MATLAB-style start when matlab_compat=True.
n_starts :
Number of deterministic optimizer starts (default 5). Ignored when
matlab_compat=True.
matlab_compat :
If True, mimic MATLAB's single random start
[1, 0, 0.2, sort(2*rand(...))] (requires rng or uses a
fresh default generator). Prefer multi-start for stable science;
use this only when reproducing a specific MATLAB Result file.
Source code in src/metasignal/stdpy/uncertainty.py
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | |
Group-level fitting
fit_group(data=None, stimuli='Stimuli', responses='Responses', confidence='Confidence', nRatings=4, subject=None, within=None, between=None, measures=None, nR_S1=None, nR_S2=None, method='mle', **bayes_kwargs)
Compute type-1 SDT and type-2 metacognitive measures for every group cell.
Parameters
data : pd.DataFrame
Trial-level DataFrame with columns for stimuli, responses, and
confidence. Subject / condition columns are optional.
stimuli : str
Column for stimulus identity (0 = S1, 1 = S2).
responses : str
Column for participant response (0 = S1, 1 = S2).
confidence : str
Column for confidence rating (integer, 1..nRatings).
nRatings : int
Number of confidence rating levels.
subject : str or None
Column identifying participants. None treats all rows as one cell.
within : str or list of str or None
Within-subjects factor column(s). When a single within-subjects
factor with exactly two levels is supplied together with
method='bayesian', fit_within_subject_comparison is used
automatically.
between : str or list of str or None
Between-subjects factor column(s). When supplied together with
method='bayesian', fit_full_metad_comparison is used.
nR_S1 : array-like or None
Count vector for S1 stimulus, length 2 * nRatings.
When provided with nR_S2, data is ignored and a single-cell
fit is run directly from counts.
Equivalent to metadpy's metad(nR_S1=..., nR_S2=...).
nR_S2 : array-like or None
Count vector for S2 stimulus (same layout as nR_S1).
method : str
Fitting method. One of:
``'mle'`` *(default)*
Frequentist MLE via :func:`fit_meta_d_mle`. Returns a tidy
DataFrame with one row per cell and 28 measure columns.
``'bayesian'``
Hierarchical Bayesian via ``metasignal.sdtbayes``. Requires
``pip install "metasignal[sdtbayes] @ git+https://github.com/saurabhr/metasignal.git"``
and ``setup_runtime()``.
The specific sdtbayes function is chosen automatically:
- No ``subject`` → ``fit_subject_level`` (single participant)
- ``subject`` only → ``fit_full_metad`` (group, no comparison)
- ``between`` set → ``fit_full_metad_comparison`` (between-groups)
- ``within`` with 2 levels → ``fit_within_subject_comparison``
- ``within`` with >2 levels → ``fit_hierarchical_metad``
Returns the raw ``FitResult`` from sdtbayes (use
``metasignal.sdtbayes.posterior_summary`` to inspect it).
``'two_stage'``
Fast two-stage Bayesian: MLE per participant then Bayesian
pooling via ``fit_two_stage_group`` / ``fit_two_stage_comparison``.
``'robust'``
Full HMeta-d with Student-t hyperprior (downweights outliers).
``'hierarchical'``
Ordered-logistic brms model (trial-level, extensible with
``items=`` for crossed effects).
**bayes_kwargs
Extra keyword arguments forwarded to the chosen sdtbayes function
(e.g. draws=2000, chains=4, target_accept=0.9,
items=[...]).
Returns
results : pd.DataFrame or FitResult
When method='mle': tidy DataFrame, one row per group cell,
28 measure columns. When any Bayesian method is chosen: the raw
FitResult from metasignal.sdtbayes (use
metasignal.sdtbayes.posterior_summary to inspect posteriors).
Examples
MLE (default), all measures, single subject:
from metasignal.stdpy import trialSimulation, fit_group df = trialSimulation(d=1.5, metad=1.5, nTrials=300) fit_group(df, nRatings=4).round(3)
Subject-level Bayesian (metadpy hmetad equivalent):
fit_group(nR_S1=nR_S1, nR_S2=nR_S2, nRatings=4, method='bayesian')
Group Bayesian — between-groups:
fit_group(df, subject='Subject', between='Group', ... nRatings=4, method='bayesian', draws=2000)
Within-subject Bayesian comparison:
fit_group(df, subject='Subject', within='Condition', ... nRatings=4, method='bayesian')
Only type-1 measures across subjects:
from metasignal.stdpy import responseSimulation, fit_group df = responseSimulation(d=1.5, metad=1.5, nSubjects=10, nTrials=200) fit_group(df, subject='Subject', nRatings=4, ... measures=['dprime', 'criterion', 'hit_rate', 'fa_rate'])
metadpy-style subset (meta-d', M_ratio, M_diff) with conditions:
from metasignal.stdpy import pairedResponseSimulation, fit_group df = pairedResponseSimulation(nSubjects=10, nTrials=200) fit_group(df, subject='Subject', within='Condition', nRatings=4, ... measures=['dprime', 'meta_d', 'M_ratio', 'M_diff'])
Source code in src/metasignal/stdpy/group.py
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | |
Plotting
Note: stdpy.plot_forest and sdtbayes.plot_forest are unrelated functions that happen to share a name — the former plots any scalar measure across subjects/conditions, the latter plots MCMC posterior forest plots.
plot_confidence(nR_S1, nR_S2, ax=None, title='Confidence rating distribution', xlabel='Rating (S1 ← → S2)')
Bar chart of response-count distributions split by stimulus class.
Parameters
nR_S1, nR_S2 :
Count vectors of length 2 * nRatings.
ax :
Existing axes to draw on. If None a new figure is created.
title, xlabel :
Axis labels.
Returns
ax : plt.Axes
Source code in src/metasignal/stdpy/plot.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | |
plot_type2roc(nR_S1, nR_S2, ax=None, show_ideal=True, label='Observed', color=_S2_COLOR, title='Type-2 ROC')
Plot the Type-2 ROC curve.
Parameters
nR_S1, nR_S2 :
Count vectors of length 2 * nRatings.
ax :
Existing axes. None creates a new figure.
show_ideal :
Overlay the ideal SDT-predicted ROC curve.
label :
Legend label for the observed curve.
color :
Line / marker colour.
title :
Axes title.
Returns
ax : plt.Axes
Source code in src/metasignal/stdpy/plot.py
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | |
plot_sanity_check(nR_S1, nR_S2, meta_d=None, title='Sanity check')
Three-panel diagnostic for a single participant.
Panels: (1) confidence distribution, (2) type-2 ROC, (3) text summary of key SDT parameters.
Parameters
nR_S1, nR_S2 :
Count vectors of length 2 * nRatings.
meta_d :
Optional pre-computed meta-d' to include in the summary panel.
title :
Figure suptitle.
Returns
fig : plt.Figure axes : np.ndarray of plt.Axes (shape (3,))
Source code in src/metasignal/stdpy/plot.py
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | |
plot_forest(data, measure, group_col=None, subject_col='Subject', ci=0.95, ax=None, title=None, palette=None)
Forest plot of a scalar measure across subjects / conditions.
Parameters
data : pd.DataFrame
Output of :func:fit_group — one row per subject (× condition).
measure : str
Column name of the measure to plot (e.g. 'M_ratio').
group_col : str or None
Column to colour-code groups / conditions. None = single colour.
subject_col : str or None
Column identifying individual subjects (plotted as points).
ci : float
Confidence interval coverage for the group mean bar (default 95 %).
ax :
Existing axes. None creates a new figure.
title : str or None
Axes title (defaults to measure name).
palette : list of str or None
Colours per group level.
Returns
ax : plt.Axes
Source code in src/metasignal/stdpy/plot.py
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | |
plot_measures(data, measures, group_col=None, ci=0.95, palette=None, figsize=None)
Bar chart comparing one or more measures across conditions / groups.
Parameters
data : pd.DataFrame
Output of :func:fit_group.
measures : str or list of str
Measure column(s) to plot. One subplot per measure.
group_col : str or None
Column used to split bars by colour.
ci : float
Confidence interval coverage (default 95 %).
palette : list of str or None
Colours per group level.
figsize : tuple or None
Figure size override.
Returns
fig : plt.Figure axes : np.ndarray of plt.Axes
Source code in src/metasignal/stdpy/plot.py
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | |
Simulation
type2_SDT_simuation(d=1.0, noise=0.2, c=0.0, nRatings=4, nTrials=500, rng=None)
Simulate Type-2 SDT response counts.
Generates nR_S1 and nR_S2 count arrays compatible with
:func:metasignal.stdpy.fit_meta_d_mle and
:func:metasignal.stdpy.trials_to_counts.
Parameters
d :
Type-1 d-prime (sensitivity).
noise :
Standard deviation of metacognitive noise added to the type-1
internal response for the type-2 judgment.
Pass a two-element list [sigma_rS1, sigma_rS2] to simulate
response-conditional noise.
c :
Type-1 decision criterion.
nRatings :
Number of confidence rating levels.
nTrials :
Number of trials to simulate.
rng :
Optional :class:numpy.random.Generator for reproducibility.
If None, uses :func:numpy.random.default_rng.
Returns
nR_S1, nR_S2 : ndarray
Response-count vectors of length 2 * nRatings.
*Ordering (same convention as metadpy / Maniscalco & Lau):*
``nR_S1[0 : nRatings]`` — S1 stimulus, S1 response, ratings high→low
``nR_S1[nRatings : 2*nRatings]`` — S1 stimulus, S2 response, ratings low→high
Same layout for nR_S2.
Examples
nR_S1, nR_S2 = type2_SDT_simuation(d=1.5, noise=0.0, c=0, nRatings=4, nTrials=1000) len(nR_S1) 8
Source code in src/metasignal/stdpy/simulate.py
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | |
type2_SDT_simuation_bayes(d=1.0, c=0.0, nRatings=4, nTrials=500, meta_noise=0.0, rng=None)
Simulate Type-2 SDT data using a Bayesian ideal observer.
Unlike :func:type2_SDT_simuation, which uses a Gaussian noise model
(noisy access to the type-1 evidence signal), this function models an
observer who bases confidence on the posterior probability of being
correct — P(correct | x) — derived via Bayes' theorem.
A noiseless observer (meta_noise=0) is metacognitively ideal:
meta-d' = d', giving M_ratio = 1 exactly. Adding meta_noise > 0
corrupts access to the posterior on the log-odds scale, reducing M_ratio
below 1 in proportion to the noise.
This implements the framework described in Fleming & Dolan (2012) and separates the metacognitive noise model from the evidence noise model.
Parameters
d :
Type-1 d-prime.
c :
Type-1 decision criterion.
nRatings :
Number of confidence rating levels.
nTrials :
Number of trials.
meta_noise :
Standard deviation of Gaussian noise added to the log-odds of
P(correct|x) before binning. Set to 0 for an ideal Bayesian
observer (M_ratio ≈ 1). Larger values reduce metacognitive
efficiency.
rng :
Optional :class:numpy.random.Generator for reproducibility.
Returns
nR_S1, nR_S2 : ndarray
Response-count vectors of length 2 * nRatings, in the same
Maniscalco & Lau convention as :func:type2_SDT_simuation.
Notes
How confidence is computed
For evidence x drawn from N(±d/2, 1):
.. math::
P(S2|x) = \sigma(d \cdot x) \quad (\text{equal priors, } c=0)
More generally with non-zero c we use the exact Gaussian ratio:
.. math::
P(S2|x) = \frac{\phi(x - d/2)}{\phi(x - d/2) + \phi(x + d/2)}
where :math:\phi is the standard normal PDF.
Confidence (posterior probability of being correct):
.. math::
p_{\text{correct}} = P(S2|x) \text{ if resp=S2, else } 1 - P(S2|x)
With meta-noise, noise is applied on the log-odds scale before converting back to probability:
.. math::
\ell_{\text{noisy}} = \text{logit}(p_{\text{correct}}) + \epsilon,
\quad \epsilon \sim N(0, \sigma_{\text{meta}})
Confidence binning
P(correct) ∈ [0.5, 1.0] is divided into nRatings equal-width bins.
The bin edges are placed at 0.5 + k * 0.5/nRatings for
k = 0, ..., nRatings. Bin index 0 = lowest confidence (P(correct)
closest to 0.5), bin index nRatings-1 = highest confidence.
Examples
Ideal observer — expect M_ratio ≈ 1:
nR_S1, nR_S2 = type2_SDT_simuation_bayes(d=1.5, meta_noise=0.0, nTrials=5000)
Noisy observer — M_ratio drops below 1:
nR_S1, nR_S2 = type2_SDT_simuation_bayes(d=1.5, meta_noise=1.0, nTrials=5000)
Source code in src/metasignal/stdpy/simulate.py
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | |
ratings2df(nR_S1, nR_S2)
Convert nR_S1 / nR_S2 count arrays to a trial-level DataFrame.
Port of metadpy.utils.ratings2df.
Parameters
nR_S1, nR_S2 :
Count vectors, length 2 * nRatings.
Returns
df : pd.DataFrame
Columns: Stimuli (0/1), Responses (0/1), Accuracy (0/1),
Confidence (1..nRatings), nTrial. Rows are shuffled.
Source code in src/metasignal/stdpy/simulate.py
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 | |
trialSimulation(d=1.0, metad=2.0, c=0.0, nRatings=4, nTrials=500, rng=None)
Simulate a single participant using closed-form SDT probabilities.
Computes exact multinomial probabilities from normal-CDF integrals and
draws counts — much faster than trial-by-trial noise simulation.
Port of metadpy.utils.trialSimulation.
Parameters
d :
Type-1 d-prime.
metad :
Type-2 meta-d' in d-prime units.
c :
Type-1 decision criterion.
nRatings :
Number of confidence rating levels.
nTrials :
Number of trials.
rng :
Optional :class:numpy.random.Generator for reproducibility.
Returns
df : pd.DataFrame
Columns: Stimuli, Responses, Accuracy, Confidence, nTrial.
Source code in src/metasignal/stdpy/simulate.py
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | |
responseSimulation(d=1.0, metad=2.0, c=0.0, nRatings=4, nTrials=500, nSubjects=1, rng=None)
Simulate responses for one or more participants.
Calls :func:trialSimulation once per subject and stacks the results.
Port of metadpy.utils.responseSimulation.
Parameters
d :
Type-1 d-prime (same for all subjects).
metad :
Meta-d' (same for all subjects).
c :
Type-1 criterion (same for all subjects).
nRatings :
Number of confidence rating levels.
nTrials :
Trials per subject.
nSubjects :
Number of subjects.
rng :
Optional :class:numpy.random.Generator.
Returns
df : pd.DataFrame
Columns: Stimuli, Responses, Accuracy, Confidence,
nTrial, Subject.
Source code in src/metasignal/stdpy/simulate.py
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 | |
pairedResponseSimulation(d=1.0, d_sigma=0.1, mRatio=None, mRatio_sigma=0.2, mRatio_rho=0.0, c=0.0, c_sigma=0.1, nRatings=4, nTrials=500, nSubjects=20, rng=None)
Simulate a two-condition repeated-measures group design.
Draws correlated M-ratio pairs per subject from a bivariate normal
distribution, then simulates both conditions via :func:trialSimulation.
Port of metadpy.utils.pairedResponseSimulation.
Parameters
d :
Group-mean type-1 d-prime.
d_sigma :
Between-subject SD for d-prime.
mRatio :
[mRatio_cond1, mRatio_cond2]. Defaults to [1.0, 0.6].
mRatio_sigma :
SD of M-ratio across subjects (applied to both conditions).
mRatio_rho :
Correlation between the two per-subject M-ratios.
c :
Group-mean type-1 criterion.
c_sigma :
Between-subject SD for criterion.
nRatings :
Number of confidence rating levels.
nTrials :
Trials per subject per condition.
nSubjects :
Number of subjects.
rng :
Optional :class:numpy.random.Generator.
Returns
df : pd.DataFrame
Columns: Stimuli, Responses, Accuracy, Confidence,
nTrial, Subject, Condition.
Source code in src/metasignal/stdpy/simulate.py
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 | |
discreteRatings(ratings, nbins=4, verbose=True, ignore_invalid=False)
Bin continuous confidence ratings into discrete levels via quantiles.
Handles floor/ceiling biases by treating extreme values as their own bin
after re-estimating inner quantile boundaries from the remaining data.
Port of metadpy.utils.discreteRatings.
Parameters
ratings :
Continuous confidence ratings (any numeric scale).
nbins :
Target number of discrete bins.
verbose :
Print a message when bias correction is applied.
ignore_invalid :
If False, raise ValueError when both floor and ceiling are
biased. Set True to proceed anyway.
Returns
discrete : np.ndarray
Integer ratings from 1 to nbins.
info : dict
'confBins', 'rebin' ([1] if corrected, else [0]),
'binCount' (per-bin trial counts).
Source code in src/metasignal/stdpy/simulate.py
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | |
analysis — Statistical inference
The analysis sub-package provides non-parametric inference tools that operate over the 26-element array (20 measures + 6 meta-d' model-fit diagnostics) produced by compute_all_measures.
bootstrap_measure(stim, resp, conf, n_ratings, measure_index, n_boot=2000, ci=0.95, rng=None)
Return a bootstrap confidence interval for one element of the 26-measure array.
Resamples trials with replacement n_boot times and computes the
requested measure on each resample. The interval is percentile-based.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stim
|
ndarray
|
Stimulus array (binary, same encoding as |
required |
resp
|
ndarray
|
Response array (binary). |
required |
conf
|
ndarray
|
Confidence rating array (1 to n_ratings). |
required |
n_ratings
|
int
|
Number of confidence rating categories. |
required |
measure_index
|
int
|
Index into the 26-element output of |
required |
n_boot
|
int
|
Number of bootstrap resamples. Default 2000. |
2000
|
ci
|
float
|
Coverage of the interval, e.g. 0.95 for a 95% CI. Default 0.95. |
0.95
|
rng
|
Generator | None
|
Optional |
None
|
Returns:
| Type | Description |
|---|---|
tuple[float, float]
|
Tuple |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/metasignal/analysis/bootstrap.py
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | |
permutation_test(stim_a, resp_a, conf_a, stim_b, resp_b, conf_b, n_ratings, measure_index, n_perm=5000, rng=None)
Two-sided permutation test for a difference in one SDT measure between conditions.
Shuffles trial condition labels n_perm times and computes the
difference in the measure on each shuffle to build a null distribution.
Returns the two-sided p-value and the observed difference.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stim_a
|
ndarray
|
Stimulus array for condition A. |
required |
resp_a
|
ndarray
|
Response array for condition A. |
required |
conf_a
|
ndarray
|
Confidence array for condition A. |
required |
stim_b
|
ndarray
|
Stimulus array for condition B. |
required |
resp_b
|
ndarray
|
Response array for condition B. |
required |
conf_b
|
ndarray
|
Confidence array for condition B. |
required |
n_ratings
|
int
|
Number of confidence rating categories (shared across conditions). |
required |
measure_index
|
int
|
Index into the 26-element output of |
required |
n_perm
|
int
|
Number of permutations. Default 5000. |
5000
|
rng
|
Generator | None
|
Optional |
None
|
Returns:
| Type | Description |
|---|---|
float
|
Tuple |
float
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/metasignal/analysis/permutation.py
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | |
group_summary(participants, n_ratings)
Compute group-level descriptive statistics over the 26-measure array.
Runs compute_all_measures for each participant and aggregates across
the group, ignoring NaN values (participants where a measure could not
be estimated are excluded from that measure's statistics).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
participants
|
list[tuple[ndarray, ndarray, ndarray]]
|
List of |
required |
n_ratings
|
int
|
Number of confidence rating categories. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Dictionary with keys: |
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
Source code in src/metasignal/analysis/group.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | |
itmc — Information-theoretic metacognition (experimental)
The itmc sub-package implements the information-theoretic metacognition framework of Dayan (2023) — Metacognitive Information Theory, Open Mind, 7, 392–411, doi:10.1162/opmi_a_00091 — measuring metacognitive sensitivity as mutual information between accuracy and confidence. meta_I, meta_Ir1, and meta_Ir2 are Dayan's own proposed measures; meta_Ir1_acc and RMI are related measures introduced by Rausch et al. (2025) — statConfR: An R Package for Static Models of Decision Confidence and Metacognition, Journal of Open Source Software, 10(106), 6966, doi:10.21105/joss.06966 — that extend Dayan's framework but aren't discussed in his original paper. It is a pre-1.0 component and its API may still change between releases. Its test suite (tests/test_itmc.py) covers bounds, monotonicity, and internal-consistency properties; backend='statconfr' is additionally cross-validated against the real R statConfR package it was ported from, and meta_I independently reproduces Dayan (2023)'s own hand-worked numerical example exactly (0.0943 vs. his published 0.094) — see analysis/itmc_comparison/ANALYSIS_REPORT.md for the full agreement report.
meta_I(stimulus, response, rating, *, backend='simple', bias_correction=False, seed=42)
Mutual information between confidence and accuracy (bits).
Parameters
stimulus, response, rating:
Trial-level arrays. stimulus/response are 0/1; rating is 1…n_ratings.
backend:
'simple': H₂(acc) − H₂(acc|conf). Fast, directly measures how
much confidence predicts correctness.
``'statconfr'``: I(stimulus; graded_response) − I_min(prior, acc).
Builds the full 2×2K joint table, computes Shannon MI, then subtracts
the analytic minimum achievable at this accuracy. Matches the R package
exactly.
bias_correction:
Subtract the estimated positive sampling bias.
'simple': permutation of accuracy labels (2000 shuffles).
'statconfr': multinomial resampling of each table row (1000 sims),
matching statConfR's bias_reduction=TRUE. Returns mean(simulated),
which can be higher or lower than the observed value.
seed:
RNG seed for bias reduction.
Source code in src/metasignal/itmc/measures.py
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | |
meta_Ir1(stimulus, response, rating, dprime=None, *, backend='simple', bias_correction=False, seed=42)
Gaussian-normalised relative metacognitive efficiency (meta-I₁ʳ).
meta-I₁ʳ = meta-I / meta-I_Gaussian(d′)
Parameters
dprime:
First-order sensitivity. If None, estimated from stimulus/response.
backend:
'simple': Gaussian reference via Monte Carlo simulation with
equal-count confidence bins.
``'statconfr'``: Gaussian reference via continuous 5000-point grid
integration of the ideal Gaussian classifier, matching the R package.
Source code in src/metasignal/itmc/measures.py
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | |
meta_Ir1_acc(stimulus, response, rating, *, backend='simple', bias_correction=False, seed=42)
Accuracy-normalised relative efficiency (meta-I₁ʳ_acc).
Normalises by Gaussian meta-I at d′ derived from observed accuracy, avoiding SDT assumptions about criterion placement.
Source code in src/metasignal/itmc/measures.py
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | |
meta_Ir2(stimulus, response, rating, *, backend='simple', bias_correction=False, seed=42)
Entropy-normalised absolute metacognitive efficiency (meta-I₂ʳ).
meta-I₂ʳ = meta-I / H₂(accuracy). Range [0, 1].
Both backends use H₂(accuracy) as the denominator; the numerator (meta-I) differs between backends.
Source code in src/metasignal/itmc/measures.py
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | |
RMI(stimulus, response, rating, *, backend='simple', bias_correction=False, seed=42)
Relative Meta-Information, range [0, 1].
RMI = (meta-I − I_min) / (I_max − I_min)
Parameters
backend:
'simple': bounds are H_s − H_r (lower) and H_s (upper) where
H_s = H₂(P(S2)) and H_r = H₂(accuracy). These bounds assume
I(S;R) as the numerator; since the simple backend uses MI(acc;conf)
instead, RMI can fall outside [0, 1] — treat as approximate.
Prefer the 'statconfr' backend for RMI.
``'statconfr'``: analytic Fano-inequality bounds
(``get_lower_info_for_one`` / ``get_upper_info_for_one`` in statConfR)
applied to I(stimulus; graded_response). RMI is properly bounded in
[0, 1] and matches the R package exactly.
Source code in src/metasignal/itmc/measures.py
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 | |
permtest_meta_I(stimulus, response, rating, *, backend='simple', n_perm=1000, seed=42)
Test whether meta-I is significantly greater than chance.
Builds a permutation null by shuffling confidence ratings across trials, which breaks the confidence–accuracy link while preserving everything else. Returns the observed value, bias-corrected value (observed − mean(null)), a one-tailed p-value, and null distribution summary statistics.
This is the IT analogue of asking "is metacognition above chance?" without fitting a parametric model.
Parameters
stimulus, response, rating :
Trial-level arrays (same conventions as meta_I).
backend :
'simple' or 'statconfr'. Both use rating permutation for the
null; the backend controls how meta-I is computed on each permuted sample.
n_perm :
Number of permutations for the null distribution.
seed :
RNG seed.
Returns
dict with keys:
observed — raw meta-I
corrected — bias-corrected meta-I (observed − mean(null))
p_value — proportion of null samples ≥ observed (one-tailed)
null_mean — mean of null distribution
null_std — std of null distribution
null — full null array (length n_perm)
backend — backend used
n_perm — number of permutations used
Source code in src/metasignal/itmc/measures.py
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | |