Between-condition dissimilarity with bootstrap confidence intervals
Source:R/rel_dissimilarity.R
rel_dissimilarity.RdQuantifies overall dissimilarity between two conditions'
group-level classification images. The primary statistic is
Euclidean distance between the two group-mean CIs, reported
both raw and normalised by sqrt(n_pixels) for cross-resolution
comparability. Percentile bootstrap 95% confidence intervals are
computed by resampling participants with replacement within each
condition.
Pair with rel_cluster_test() when you also want to know
where the two conditions differ.
Usage
rel_dissimilarity(
signal_matrix_a,
signal_matrix_b,
paired = FALSE,
n_boot = 2000L,
ci_level = 0.95,
null = c("none", "permutation"),
n_permutations = 2000L,
mask = NULL,
seed = NULL,
progress = TRUE,
acknowledge_scaling = FALSE
)Arguments
- signal_matrix_a, signal_matrix_b
Pixels x participants, base-subtracted. Row counts must match.
- paired
Logical.
FALSE(default) for between-subjects: participants resampled within A and B independently.TRUEfor within-subjects: A and B share a single resample index per replicate so the paired covariance structure is preserved.- n_boot
Bootstrap replicates. Default 2000.
- ci_level
Confidence level. Default 0.95.
- null
One of
"none"(default) or"permutation"."permutation"builds an empirical chance baseline for the Euclidean distance.- n_permutations
Integer. Number of null iterations when
null = "permutation". Default 2000.- mask
Optional logical vector of length
nrow(signal_matrix_a)(column-major) restricting the Euclidean / correlation computation to a region. Build withmake_face_mask()(parametric oval and sub-regions) orread_face_mask()(PNG/JPEG mask).- seed
Optional integer; RNG state restored on exit.
- progress
Show a
cliprogress bar.- acknowledge_scaling
Logical. When
FALSE(default), the sharedassert_raw_signal()helper errors on a known-rendered matrix on either side.
Details
For the observed statistics and each bootstrap replicate i:
mean_a = rowMeans(signal_matrix_a)
mean_b = rowMeans(signal_matrix_b)
observed_dist = sqrt(sum((mean_a - mean_b)^2))
observed_dist_normalised = observed_dist / sqrt(n_pixels)Percentile CI via base R quantile(); no boot dependency.
Why Euclidean and not Pearson correlation as the primary
Two base-subtracted CIs share systematic image-domain spatial
structure (face shape, oval signal support, low-frequency
Gaussian-noise smoothness) that pushes their correlation above
zero even when the underlying mental representations are
unrelated. Absolute correlation values therefore do not cleanly
mean "these conditions are similar". Euclidean distance does
not share this failure mode. The Pearson correlation fields
($correlation, $boot_cor, $ci_cor, $boot_se_cor) are
retained for backwards compatibility and slated for removal in
a future release.
Reading the plot
plot() on the returned object renders the bootstrap
distributions as two side-by-side histograms (Euclidean
distance on the left, Pearson r on the right; the latter is
deprecated and shown in grey).
The shaded vertical band marks the percentile CI at
ci_level.The vertical line marks the observed statistic on the real data (not a bootstrap mean).
A non-overlapping CI band away from zero on the Euclidean panel indicates the two group-mean CIs sit a non-trivial distance apart in pixel space, robust to participant-level resampling. The numbers are returned in
$ci_dist.For visual comparison across multiple contrasts, pass each
rel_dissimilarity()result toplot_dissimilarity_grid(), which lays them out as labelled CI bars on a shared axis.For a spatial picture of where the two conditions differ, pair this with
rel_cluster_test()(or userun_discriminability()to run both in one call).
Reading the result
$euclidean, observed Euclidean distance between group means (primary statistic).$euclidean_normalised,$euclidean / sqrt(n_pixels). Use for cross-resolution comparisons.$boot_dist,$ci_dist,$boot_se_dist, bootstrap distribution, percentile CI, and SE of the Euclidean distance.$null(character), the null mode used.$null_distribution, whennull != "none": numeric vector of per-iteration Euclidean distances under the chosen null.$d_null_p95, 95th percentile of the null distribution.$d_z, z-equivalent effect size:(observed_d - mean(null)) / sd(null).$d_ratio, observed Euclidean over the null median.$correlation,$boot_cor,$ci_cor,$boot_se_cor: Pearson correlation of the group means. Deprecated; see above.$n_boot,$ci_level,$paired, metadata.
References
Efron, B., & Tibshirani, R. J. (1994). An introduction to the bootstrap. Chapman & Hall / CRC.
Examples
if (FALSE) { # \dontrun{
# Minimal call-signature demo with two synthetic inputs.
n_pix <- 32L * 32L
n_prod <- 20L
set.seed(1)
signal_matrix_a <- matrix(rnorm(n_pix * n_prod), n_pix, n_prod)
signal_matrix_b <- matrix(rnorm(n_pix * n_prod), n_pix, n_prod)
rel_dissimilarity(signal_matrix_a, signal_matrix_b,
n_boot = 200L, seed = 1)
} # }
if (FALSE) { # \dontrun{
# Same function, richer input: signal planted in different face regions
# (eyes vs mouth). The Euclidean distance and its bootstrap CI should
# be well above zero, reflecting genuine spatial divergence.
sim_eyes <- simulate_briefrc_data(
n_per_condition = 20, n_trials = 60, conditions = "x",
signal_region = "eyes", signal_strength = "strong", seed = 1
)
sim_mouth <- simulate_briefrc_data(
n_per_condition = 20, n_trials = 60, conditions = "x",
signal_region = "mouth", signal_strength = "strong", seed = 2
)
sig_eyes <- ci_from_responses_briefrc(
sim_eyes$data, noise_matrix = sim_eyes$noise_matrix)$signal_matrix
sig_mouth <- ci_from_responses_briefrc(
sim_mouth$data, noise_matrix = sim_mouth$noise_matrix)$signal_matrix
d <- rel_dissimilarity(sig_eyes, sig_mouth, n_boot = 500L, seed = 1)
# Bootstrap distribution + observed Euclidean + 95% CI band.
plot(d, main = "Eyes vs Mouth: bootstrap dissimilarity")
} # }