This document describes the analysis pipeline for the Delayed Conditional Discrimination (DCD) comparative cognition study across eight animal species. The pipeline computes learning metrics, correlates them with brain size (neuron count and brain volume), and provides statistical inference through exact permutation tests and bootstrap confidence intervals.
| File | Description |
|---|---|
data/IndividualBinnedData_DCD.csv |
Main-analysis input: subject-level binned learning data. Expected 6 columns in order: SubjectID, Species, Bin, Correct Num, Total Trials, Prop % |
data/DCD_SpeciesTests_noShps.csv |
Main-analysis input: test performance per individual. Expected columns: Species, SpeciesID, Perf |
data/DCD_SpeciesLearningCurves_noShps.csv |
Validation-script input (used by Brains_data_validation.py): aggregated learning curves per species and bin (Species, Block, Mean, StErr, lowerBound) |
Brains_main_analysis.py consumes IndividualBinnedData_DCD.csv and DCD_SpeciesTests_noShps.csv.
DCD_SpeciesLearningCurves_noShps.csv is used for aggregated-vs-raw consistency checks in Brains_data_validation.py.
Eight species ordered by neuron count:
| Species (task/proxy) | Neuron/cell count | Brain volume (mm³) | Primary source |
|---|---|---|---|
| 1. Salamander (Ambystoma tigrinum) | 4.77 × 10⁵ | 30.7 | Proxy: Axolotl telencephalon scaled to tiger salamander (Kaplan et al. 2025 + Lazcano et al. 2021) |
| 2. Bumblebee (Bombus terrestris) | 5.57 × 10⁵ | 2.29 | Proxy: Bombus impatiens nuclei (Godfrey et al. 2021) |
| 3. Honeybee (Apis mellifera) | 6.13 × 10⁵ | 2.10 | Godfrey et al. (2021) |
| 4. Tortoise (Testudo sp.) | 9.07 × 10⁶ | 590.5 | Proxy: Testudo marginata (Kverková et al. 2022) |
| 5. Hummingbird (ruby-throated) | 1.63 × 10⁸ | 115.8 | Proxy: Goldcrest Regulus regulus (Olkowicz et al. 2016) |
| 6. Chicken (Gallus gallus) | 2.21 × 10⁸ | 994.2 | Olkowicz et al. (2016) |
| 7. Blue jay (Cyanocitta cristata) | 1.085 × 10⁹ | 2921.0 | Proxy: Eurasian jay Garrulus glandarius (Olkowicz et al. 2016) |
| 8. Capuchin (Sapajus spp.) | 3.69 × 10⁹ | 66630.0 | Herculano-Houzel et al. (2007) |
Notes on neuron/cell counts:
- Salamander: Axolotl telencephalon mean cells = 171,418 (Kaplan et al. 2025). Scaled to tiger salamander whole-brain volume (30.7 mm³ from Latimer & Roofe 1964) yields ~477,000 cells.
- Bee counts are nuclei counts from Godfrey et al. (2021).
- Brain volumes derived from mass measurements using density ≈ 1.036 g/cm³ (Kverková et al. 2022).
According to the experimental protocol, training continued until capuchins reached a learning criterion (>70% correct in the last 20 trials; 15/20) or until a maximum of 45 sessions (540 trials). Only two capuchins out of five were deemed learners according to the criterion and therefore tested.
For the analysis we require a test-performance value for all trained individuals. Missing capuchin test scores are imputed from terminal training performance using Brains_predict_test_from_training.py for selecting the imputed capuchin value.
The TTC is computed using the lower-bound curve (mean − SEM) with EMA smoothing:
EMA[0] = lb[0]
EMA[i] = α × lb[i] + (1 − α) × EMA[i−1]
Where:
lb[i]= lower bound at bin i (mean − SEM)α= 0.35 (smoothing parameter)- Threshold = 0.5 (50% correct)
The EMA coefficient α = 0.35 is data-driven: it is fitted using Brains_time_constant.py by scanning α values (0.05 to 0.95) and selecting the value that minimises one-step-ahead predictive mean squared error across subject PropCorrect time series.
thr_eff = threshold - TOLERANCE
for i in range(len(bins)):
if ema[i] > thr_eff:
return bin[i]
return NON_LEARNERS_LOWER_BOUND # Never met criterionSpecies that never reach criterion (capuchin) are assigned:
NON_LEARNERS_LOWER_BOUND = MAX_BINS + 1 = 109(one bin beyond maximum observed)- Speed = 1/109 ≈ 0.0092
For the TTC vs brain size analysis, non-learners are patched at 109 bins rather than infinity to allow meaningful regression analysis.
| Species | N subjects | TTC (bin) | Classification |
|---|---|---|---|
| Salamander | 9 | 13 | Learner |
| Bumblebee | 20 | 6 | Learner |
| Honeybee | 22 | 6 | Learner |
| Tortoise | 6 | 14 | Learner |
| Hummingbird | 10 | 12 | Learner |
| Chicken | 9 | 6 | Learner |
| Blue jay | 4 | 10 | Learner |
| Capuchin | 5 | 109 | Non-learner → 109 |
- Speed = 1/TTC (learning rate)
- Test Performance = Final test phase accuracy
Both components are z-scored across all 8 species:
z_speed = (speed - mean(speeds)) / std(speeds)
z_test = (test - mean(tests)) / std(tests)composite(w) = w × z_speed + (1 − w) × z_testWhere w ranges from 0.01 to 0.99.
To avoid arbitrary weight selection, the final composite is the mean across all weights, with confidence intervals from bootstrap resampling:
weights = np.linspace(0.01, 0.99, 99)
composites = [w * z_speed + (1-w) * z_test for w in weights]
composite_score = np.mean(composites)- X: log₁₀(neuron count) or log₁₀(brain volume in mm³) for each species
- Y: Composite score, Speed, or log(TTC)
Pearson correlation computed on ranks, with ties receiving the average of the ranks they would occupy.
Standard Pearson product-moment correlation on the raw (non-ranked) values.
For weighting by sample size (N subjects per species):
def weighted_pearson_r(x, y, weights):
w = weights / weights.sum()
x_mean = sum(w * x)
y_mean = sum(w * y)
cov_xy = sum(w * (x - x_mean) * (y - y_mean))
var_x = sum(w * (x - x_mean)²)
var_y = sum(w * (y - y_mean)²)
return cov_xy / sqrt(var_x * var_y)For TTC vs brain size analysis with sample-size weighting, using the WLS formula: β = (X'WX)⁻¹X'Wy.
For N=8 species, there are 8! = 40,320 possible permutations of Y. All permutations are enumerated exactly (no Monte Carlo sampling needed).
P-value definitions:
p_two: P(|stat_perm| ≥ |stat_obs|) — two-sidedp_one_neg: P(stat_perm ≤ stat_obs) — left tail (for negative associations)p_one_pos: P(stat_perm ≥ stat_obs) — right tail (for positive associations)
Interpretation:
- For brain vs composite/speed: one-sided negative test (bigger brains → worse learning)
- For brain vs TTC: one-sided positive test (bigger brains → more trials to learn)
Sample sizes:
- Correlation CIs (Pearson/Spearman): B = 20,000 bootstrap resamples
- Slope CIs: B = 20,000 bootstrap resamples
- TTC correlation CIs: B = 20,000 bootstrap resamples
- Rank/composite CIs: B = 20,000 bootstrap resamples
Methods:
- Percentile method: CI bounds are directly from bootstrap distribution percentiles
- Rejection sampling: Degenerate samples (constant vectors) are skipped
- P(slope > 0): Fraction of bootstrap slope estimates that are positive
When using random permutations (N > 8), the "+1 correction" is applied to avoid p = 0:
p = (count_extreme + 1) / (n_perm + 1)This is not needed for N=8 since exact enumeration is used.
| Method | What It Tests |
|---|---|
| Permutation test | "Could this correlation arise by chance?" (null hypothesis testing) |
| Bootstrap CI | "What range of correlations is consistent with this data?" (estimation uncertainty) |
With N=8:
- Permutation is exact (enumerates all 40,320 possibilities)
- Bootstrap is approximate and sensitive to influential points
- A significant permutation p-value with CI crossing zero indicates high uncertainty despite statistical significance
This analysis tests whether larger-brained species require more trials to reach the learning criterion. We correlate log(TTC) with log₁₀(neuron count) and log₁₀(brain volume) across the 8 species.
Unweighted Analysis:
- Pearson r between brain size and log(TTC)
- Spearman ρ (rank correlation)
- OLS regression: log(TTC) = β₀ + β₁ × brain_size
- Bootstrap CIs for r and slope (B = 20,000)
- Exact permutation tests (all 8! = 40,320 permutations)
N-Weighted Analysis (optional):
- Weighted Pearson r (species weighted by N subjects)
- Weighted least squares regression
- Bootstrap CIs
- Permutation tests for weighted slope
There is evidence for a positive relationship between brain size and TTC (larger-brained species take longer to learn), though the relationship is influenced by the capuchin non-learner status. The analysis is run separately for both neuron count and brain volume as predictors.
The main figure contains 6 panels:
| Panel | Content |
|---|---|
| A | Learning curves (mean ± SEM) reconstructed from raw individual data |
| B | Test performance (mean ± SEM) per species |
| C | Rank trajectories across weight values w ∈ [0.01, 0.99] |
| D | Mean rank with bootstrap 95% CI |
| E | Brain size (neuron count) vs composite score scatter (with regression line) |
| F | Brain volume vs composite score scatter (with regression line) |
A separate figure contains 2 panels:
| Panel | Content |
|---|---|
| A | TTC vs neuron count scatter (log-log, with regression line) |
| B | TTC vs brain volume scatter (log-log, with regression line) |
Non-learner species (capuchin) are shown with square markers.
The codebase follows a modular structure separating concerns:
| File | Purpose | Description |
|---|---|---|
libraries/Brains_config.py |
Configuration | All parameters, constants, species data |
libraries/Brains_stats.py |
Statistics | Correlation, regression, permutation, bootstrap |
libraries/Brains_lib.py |
Data & TTC | Data loading, TTC computation, plotting utilities |
libraries/Brains_log.py |
Logging | Output logging and report generation |
Brains_main_analysis.py |
Main analysis | Composite scores, correlations, figures |
libraries/Brains_config.py (standalone - no dependencies)
libraries/Brains_stats.py (standalone - numpy, scipy)
libraries/Brains_lib.py (standalone - numpy, matplotlib)
libraries/Brains_log.py (standalone)
↓
Analysis scripts (import from all above)
libraries/Brains_lib.py (Data & Computation):
| Function | Purpose |
|---|---|
load_structured_csv() |
Load CSV with type validation and row-skip warnings |
compute_ttc_from_curve() |
Unified TTC computation (EMA or run-rule modes) |
compute_ttc_across_species() |
Species-level TTC from reconstructed curves |
beautify_ax() |
Consistent plot styling |
libraries/Brains_stats.py (Statistics):
| Function | Purpose |
|---|---|
pearson_r(), spearman_rho() |
Correlation coefficients with NaN handling |
linregress() |
Linear regression (scipy wrapper) |
leave_one_out_regression() |
LOO cross-validation returning slope, r, ρ per exclusion |
spearman_permutation_test_two_tails() |
Exact permutation test (both one-sided p-values) |
pearson_permutation_test_two_tails() |
Exact permutation test (both one-sided p-values) |
permutation_test_slope() |
Permutation test for regression slope |
bootstrap_slope_ci() |
Bootstrap CI for slope with P(slope > 0) |
weighted_pearson_r() |
Sample-size weighted correlation |
weighted_linregress() |
Weighted least squares regression |
weighted_pearson_bootstrap_ci() |
Bootstrap CI for weighted Pearson r |
Per-analysis RNG streams ensure reproducibility and order-invariance:
seed = zlib.crc32(f"{GLOBAL_SEED}:{block_offset}:{species_name}")
rng = np.random.default_rng(seed)When USE_FIXED_SEED = True, results are fully reproducible. When False, true randomness is used.
- Python 3.8+
- NumPy (array operations, statistics)
- SciPy (correlation, regression via
scipy.stats) - Matplotlib (figure generation)
Panel D (Mean Rank) and Panel E (Mean Composite) may show different orderings because rank(mean) ≠ mean(rank).
| Species | Z(speed) | Z(test) |
|---|---|---|
| Tortoise | −0.546 | −0.913 (poor) |
| Capuchin | −1.745 (worst) | +0.145 (decent) |
At low weights (test-dominated), capuchin ranks better than tortoise. At high weights (speed-dominated), capuchin ranks worst. The mean rank averages these positions, while mean composite averages the scores directly.
The TTC figure shows brain size vs log(TTC) for both neuron count and brain volume. Key observations:
- Positive slope: Larger-brained species tend to require more trials to reach criterion
- Non-learner: Capuchin (■) is patched at 109 bins
- Two panels: Panel A uses neuron count, Panel B uses brain volume
- Correlation metrics: Both Spearman ρ and Pearson r are shown in panel titles
Two brain size metrics are used throughout the analysis:
Total brain neuron/cell counts from the literature. For species where direct counts are unavailable, proxy species with similar brain sizes are used (see Section 1.2).
Whole-brain volumes in mm³ taken from the literature.
Both metrics show similar patterns but can differ in their relationship to cognitive performance due to differences in neuron density across species and brain regions.
All regression analyses include leave-one-out (LOO) cross-validation to assess robustness. For each species excluded:
loo = leave_one_out_regression(x, y, species_labels)
# Returns: {species: {"slope": float, "r": float, "rho": float}}Interpretation:
- If all LOO slopes have the same sign → result is robust
- If LOO slopes change sign → result depends heavily on specific species
- Large changes when excluding one species → that species is influential
The leave_one_out_regression() function in libraries/Brains_stats.py supports optional weights for weighted regression LOO analysis.
Key configuration parameters in Brains_main_analysis.py:
| Parameter | Default | Description |
|---|---|---|
TTC_MODE |
"ema" | TTC algorithm: "ema" or "run" |
EXP_ALPHA |
0.35 | EMA smoothing coefficient |
EMA_DIRECTION |
"forward" | Direction of EMA search |
BINS_THRESHOLD |
0.5 | Performance threshold for criterion |
NON_LEARNERS_TTC |
109 | TTC value assigned to non-learners |
PATCH_TEST_VALUE |
0.576 | Test score for missing test subjects |
B_BOOTSTRAP |
20000 | Number of bootstrap resamples |
B_CI |
20000 | Bootstrap samples for correlation CIs |
TTC_WEIGHT_MODE |
"none" | Weighting: "none", "N", or "precision" |