Skip to content

Scale the input once in OneD_SymbolicAggregateApproximation - #721

Open
VenishPaneliya wants to merge 3 commits into
tslearn-team:mainfrom
VenishPaneliya:1dsax-double-scaling
Open

Scale the input once in OneD_SymbolicAggregateApproximation#721
VenishPaneliya wants to merge 3 commits into
tslearn-team:mainfrom
VenishPaneliya:1dsax-double-scaling

Conversation

@VenishPaneliya

Copy link
Copy Markdown

OneD_SymbolicAggregateApproximation._transform scales X and then passes it to SymbolicAggregateApproximation._transform, which scales it again:

def _transform(self, X, y=None):
    X = self._scale(X)
    ...
    X_1d_sax_avg = SymbolicAggregateApproximation._transform(self, X)   # scales again

_scale uses the fitted mu_ and std_, so it is not idempotent — the average symbols end up computed from ((X - mu) / std - mu) / std. The slopes are fine, since they are derived separately.

With scale=True on data that is not already standardised, the average symbols collapse. For a series with mean 10 and standard deviation 5:

X = np.random.RandomState(0).randn(4, 12, 1) * 5 + 10
SymbolicAggregateApproximation(n_segments=4, alphabet_size_avg=5, scale=True).fit_transform(X)
OneD_SymbolicAggregateApproximation(n_segments=4, alphabet_size_avg=5,
                                    alphabet_size_slope=5, scale=True).fit_transform(X)[:, :, :1]
SAX     [3 3 2 3 2 3 0 2 2 3 1 1 3 0 2 1]     4 of 5 symbols used
1d-SAX  [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]     1 of 5 symbols used

Every segment lands in the same symbol, so the average half of the representation carries no information. inverse_transform also unscales only once, so the round-trip does not return to the input scale.

This lets the parent do the scaling for the average, and scales explicitly for the slopes, which need the scaled series as well.

Scope:

  • scale=False, the default, is unchanged — average and slope symbols are identical before and after.
  • With scale=True the slope symbols are also unchanged; only the average symbols move, and they now match SymbolicAggregateApproximation exactly.
  • It does change the average symbols for anyone currently using scale=True. That output is degenerate today rather than merely different, which is why it seemed worth correcting rather than leaving.

The existing test_1dsax exercises scale=True but only asserts that distance and distance_1d_sax agree with each other, so it passes either way. The added test compares the average symbols against SymbolicAggregateApproximation; it fails on main and passes here. tests/test_piecewise.py goes 4 -> 5 passing, and tests/test_estimators.py for the SAX/piecewise estimators is 127 passed, 3 skipped.

`OneD_SymbolicAggregateApproximation._transform` scales `X` and then
hands it to `SymbolicAggregateApproximation._transform`, which scales it
again. `_scale` uses the fitted `mu_` and `std_`, so it is not
idempotent and the average symbols are computed from
`((X - mu) / std - mu) / std`.

With `scale=True` on data that is not already standardised the average
symbols collapse. For a series with mean 10 and standard deviation 5,
1d-SAX puts all 16 segments in a single symbol while SAX uses four:

    SAX    [3 3 2 3 2 3 0 2 2 3 1 1 3 0 2 1]
    1d-SAX [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

Let the parent do the scaling for the average, and scale explicitly for
the slopes, which need the scaled series too.

`scale=False`, the default, is unchanged, and the slope symbols are
unchanged in both cases - only the average symbols under `scale=True`
move, and they now match SAX exactly.
@codecov

codecov Bot commented Aug 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.31%. Comparing base (48f2ae6) to head (4e565b2).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #721      +/-   ##
==========================================
+ Coverage   94.35%   95.31%   +0.95%     
==========================================
  Files          83       83              
  Lines        7990     7996       +6     
==========================================
+ Hits         7539     7621      +82     
+ Misses        451      375      -76     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@charavelg

Copy link
Copy Markdown
Contributor

Hi @VenishPaneliya , thanks for the contribution, that's a nice catch!!!

Would you mind opening a related issue and reference it in a changelog entry? That would make both the issue and the fix more visible!!!

Happy to help in anyway if needed

@charavelg charavelg linked an issue Aug 28, 2026 that may be closed by this pull request
@VenishPaneliya

Copy link
Copy Markdown
Author

Thanks — and apologies, I opened #723 before spotting that you'd already filed #722 and added the changelog entry. I've closed mine as a duplicate; #722 is the right one to keep.

Nothing outstanding from my side then, unless you'd like the entry reworded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scale the input once in OneD_SymbolicAggregateApproximation

2 participants