Orientation Driver Attribution
Orientation attribution explains a two-group, multi-stage difference after an
upstream trajectory analysis has identified the shared PLS space of interest.
Pass the pooled, aligned feature matrix, matching group/stage metadata, and
the one fitted PLS estimator to analyze_orientation_attribution.
The analysis orders groups and stages deterministically unless explicit levels
are supplied. For every adjacent stage pair it reports each group's raw
transition and path length, the unit directional contrast, the same contrast
after PLS score projection and inverse transformation, and the signed residual
observed - pls_captured. Observed feature values remain in the result; the
reconstruction is a parallel, lossy view rather than a replacement.
Two decompositions
Attribution reports two decompositions, and they explain different quantities.
The principal-orientation block decomposes the tested angle estimand:
principal-axis divergence, the contrast between the groups' signed leading
principal axes. It applies the same functional the statistic is built from
(motco.stats.trajectory.principal_orientation) to each group's stage-mean
configuration, observed and PLS-reconstructed, so the explanation and the test
cannot drift apart.
The per-adjacent-transition blocks describe where along the trajectory the groups' step directions diverge. They are a per-step description, not the tested estimand; the two decompositions coincide only for a two-stage design, where the configuration is rank one and PC1 is the transition direction.
Both appear in the tabular outputs under the transition_id column — the
transitions as from->to, the principal block under principal_component_id
(default principal), which is validated against the stage-derived identifiers
so the two can never collide.
Degeneracy and availability
A principal axis exists for any configuration with variance, but it is only
resolvable when one axis dominates. The result reports each contributing
configuration's relative eigengap and flags the principal contrast degenerate
when any falls below eigengap_threshold (default 0.05). The flagged contrast
is still returned: degeneracy is a property of the data, so callers stratify on
the flag rather than lose rows.
That is distinct from unavailability. A trajectory whose net displacement from
first stage to last is at or below zero_tolerance is closed, and no direction
is defined at all — that group's principal orientation is marked unavailable,
exactly as a zero-length transition is.
Units and stability
Effects are reported in the input coordinate units, normally pooled standardized units. Positive per-feature scales can be supplied to add original-unit columns. These scales only convert reported effects; they never change PLS geometry.
Bootstrap resampling is independent within every group-by-stage cell and uses the same fitted model and preprocessing contract in every replicate. The result records the seed, requested count, valid count, sign stability, and top-k selection frequency, for the principal-orientation block as well as the transitions. Each replicate's principal axis is signed by that replicate's own net displacement, so resampling noise cannot flip the axis; a replicate whose trajectory closes contributes no contrast and counts as invalid. Bootstrap is available for arithmetic row-derived means; precomputed covariate-adjusted mean tables are accepted with stability marked unavailable.
Labels and interpretation
Feature-to-module or feature-to-pathway labels are optional and must be a
complete one-to-one mapping supplied by the caller. Aggregate tables preserve
the labels and mark their source as caller-supplied. Aggregation is not a
pathway annotation service and does not establish biological causality.
The result contains no p-values or significance decisions. Attribution should be run after the calling workflow has made any global orientation inference decision. It describes associations implied by one frozen shared PLS model; the inverse reconstruction is not unique, and bootstrap stability is conditional on that fitted representation.
Functions
motco.stats.attribution.analyze_orientation_attribution(X, metadata, model, *, group_col='group', stage_col='stage', feature_cols=None, groups=None, stages=None, mean_table=None, precomputed_means=None, original_scales=None, feature_scales=None, feature_groups=None, group_labels=None, label_namespace='module', bootstrap_replicates=0, bootstrap_seed=0, top_k=10, zero_tolerance=1e-12, eigengap_threshold=0.05, principal_component_id='principal', sample_id_col=None)
Attribute two-group trajectory orientation differences.
Reports both decompositions described in the module docstring: the
principal-orientation contrast, which decomposes the tested angle
estimand and carries a relative-eigengap degeneracy qualifier, and the
per-adjacent-transition contrasts, which describe where along the trajectory
the group directions diverge. The two coincide only for a two-stage design.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
DataFrame
|
Aligned feature matrix in the exact coordinate system consumed by
|
required |
metadata
|
DataFrame
|
Row-aligned metadata containing |
required |
model
|
Any
|
One already fitted pooled PLS estimator exposing |
required |
mean_table
|
DataFrame | None
|
Optional complete group-by-stage table. It may have a two-level MultiIndex or explicit group/stage columns. When supplied, bootstrap resampling is unavailable because row-level sampling semantics are not defined for adjusted means. |
None
|
precomputed_means
|
DataFrame | None
|
Optional complete group-by-stage table. It may have a two-level MultiIndex or explicit group/stage columns. When supplied, bootstrap resampling is unavailable because row-level sampling semantics are not defined for adjusted means. |
None
|
original_scales
|
Sequence[float] | Series | Mapping[str, float] | None
|
Optional positive per-feature scale in canonical feature order. The aliases are accepted for readability at call sites; supplying both is an error. |
None
|
feature_scales
|
Sequence[float] | Series | Mapping[str, float] | None
|
Optional positive per-feature scale in canonical feature order. The aliases are accepted for readability at call sites; supplying both is an error. |
None
|
feature_groups
|
Mapping[str, str] | Series | DataFrame | None
|
Optional one-to-one caller-supplied feature-to-label mapping. The aliases are accepted for readability at call sites. |
None
|
group_labels
|
Mapping[str, str] | Series | DataFrame | None
|
Optional one-to-one caller-supplied feature-to-label mapping. The aliases are accepted for readability at call sites. |
None
|
eigengap_threshold
|
float
|
Relative-eigengap level at or above which a stage-mean configuration is treated as having a well-separated principal axis. A contributing configuration below it flags the principal-orientation contrast as degenerate; the contrast is still returned, so callers stratify rather than lose rows. The default (0.05) separates the audit's resolvable replicates from its near-isotropic independent-baseline draws. |
0.05
|
principal_component_id
|
str
|
Reserved identifier carrying the principal-orientation component in the
tabular outputs' |
'principal'
|
Returns:
| Type | Description |
|---|---|
OrientationAttributionResult
|
Frozen typed records and DataFrame views for means, transitions, the principal-orientation block, feature effects, aggregates, and bootstrap stability. |
Source code in src/motco/stats/attribution.py
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 324 325 326 327 328 329 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 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 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 | |
motco.stats.attribution.attribution_frames(result)
Return all findings-ready tables for result.
Source code in src/motco/stats/attribution.py
510 511 512 513 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 | |
motco.stats.attribution.write_attribution_outputs(result, output_dir)
Write attribution tables as CSV files and return their paths.
Source code in src/motco/stats/attribution.py
562 563 564 565 566 567 568 569 570 571 572 573 574 575 | |