Repository navigation
Segmental coordination: many markers on one axis, not each on its own - #3
Merged
Merged
Conversation
MGT #358 asked for three things: inter-segment correlation along a shared sway axis, effective degrees of freedom across markers, and a head-to-hip amplitude ratio. Markers are this package's domain, so they land here. ONE OF THE THREE ALREADY EXISTED. effective_dimensionality computes the participation ratio the effective-DOF metric wants, and called with rank=False it reproduces the still-standing analysis's pc1 and eff_dof on all 81 sessions to 1e-10. It is called rather than copied --- that module's own docstring says the arithmetic drifted between report copies, which is why it is there at all. rank=False is load-bearing and now has a test that fails under rank=True: ranking discards amplitude, and amplitude is the whole content of a projection. WHAT WAS ACTUALLY MISSING is the projection. principal_axis_projection gives each marker its OWN axis, and two markers swaying at right angles, each on its own axis, correlate perfectly while sharing no direction of motion at all. Correlating segments only means something once they are on one axis, and that axis has to come from a named marker, because it is anatomical rather than a property of the pooled cloud. Verified against the study that asked for it, not only against synthetic data: correlations reproduce to 4e-16 on every session it produced a number for, and the amplitude ratio to 4e-16 on the 79 of 81 sessions where both hip markers are present throughout. The two that differ are exactly the two with frames where one hip is missing, which is a caller-side construction choice --- the study averages the two projections, so a one-hip frame uses the surviving marker's centred signal --- and both are reachable through these functions. THREE THINGS THE STUDY CODE DID NOT DO. Correlations are pairwise-complete and each carries its own n: np.corrcoef returns NaN if one sample is missing, which dropped one or two sessions per pair into a dropna() beneath a heading that reported a single N for every row. mask chooses between the study's convention and each marker's own, so that coupling is a decision rather than an accident. And reduce names which markers enter the reduction, because a derived marker wanted only for a ratio is a linear combination of segments already present --- found by testing against the real data, where it moved eff_dof by 0.16. Every guard was checked by removing it and watching its test fail. All twelve passed on first run, and a check that cannot fail is worth nothing. No body-part taxonomy is built in. "Inverted pendulum" is an interpretation of a ratio above one, not something this computes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xg1f739wddu5M4s3UwdNkn
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements MGT #358. Markers are this package's domain, so the work lands here and MGT closes with a pointer — the same shape as #356 and #357.
One of the three metrics already existed
effective_dimensionalitycomputes the participation ratio the effective-DOF metric wants. Called withrank=Falseit reproduces the still-standing analysis'spc1andeff_dofon all 81 sessions to 1e-10. So it is called, not copied — that module's own docstring records the arithmetic drifting between report copies, which is why it exists.rank=Falseis load-bearing and now has a test that fails underrank=True. Ranking is right for heavy-tailed descriptors and wrong here: it discards amplitude, and amplitude is the whole content of a projection.What was actually missing
The projection.
principal_axis_projectiongives each marker its own axis — and two markers swaying at right angles, each on its own axis, correlate perfectly while sharing no direction of motion at all. Correlating segments only means something once they are on one axis, and that axis must come from a named marker because it is anatomical, not a property of the pooled cloud.Verified against the study that asked for it
pc1,eff_dofThe 2 sessions that differ are exactly the 2 with frames where one hip marker drops out — a caller-side construction choice (the study averages the two projections, so a one-hip frame uses the surviving marker's centred signal). Both are reachable through these functions.
Three things the study code did not do
n.np.corrcoefreturns NaN if one sample is missing, dropping 1–2 sessions per pair into adropna()beneath a heading that reported a single N for every row.maskchooses between the study's convention (every marker masked by the reference marker's valid frames) and each marker's own, so the coupling is a decision rather than an accident.reducenames which markers enter the reduction. A derived marker wanted only for a ratio — a hip midpoint — is a linear combination of segments already present, and silently entering it as a ninth changedeff_dofby 0.16. Found by testing against the real data.Testing
12 tests, all synthetic known-answer. All passed on first run, so each guard was checked by removing it and watching its test fail. Full suite 397 passed, 2 skipped.
No body-part taxonomy is built in — "inverted pendulum" is an interpretation of a ratio above one, not something this computes.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Xg1f739wddu5M4s3UwdNkn