Enable out-of-sample transform with precomputed_affinity - #183
Open
MattScicluna wants to merge 1 commit into
Open
Enable out-of-sample transform with precomputed_affinity#183MattScicluna wants to merge 1 commit into
MattScicluna wants to merge 1 commit into
Conversation
PHATE.transform() previously raised a ValueError for any precomputed graph, including knn_dist="precomputed_affinity". Unlike distances, a precomputed query-train affinity matrix is already a usable transition kernel, so no new kernel needs to be built. transform() now recognizes this case and computes the out-of-sample embedding directly: row-normalize the query-train affinity (or, when the graph was fit with landmarks, first aggregate by landmark cluster and then row-normalize) and apply it to the fitted embedding. Fixes KrishnaswamyLab#181
There was a problem hiding this comment.
Pull request overview
This PR updates PHATE.transform() to support out-of-sample projection when the operator was fit with a precomputed affinity graph (including landmark mode), aligning behavior with Issue #181’s requested P_query-train · Z_train / P_query-landmark · Z_landmark extension.
Changes:
- Adds out-of-sample transform support for
knn_dist="precomputed_affinity"by row-normalizing query→train affinities (and aggregating to landmarks when applicable). - Refactors embedding creation into
_ensure_embedded()and introduces_transform_precomputed_affinity()helper. - Adds regression tests for out-of-sample transform with precomputed affinities (with and without landmarks).
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| Python/phate/phate.py | Implements out-of-sample transform path for precomputed affinities and refactors embedding initialization. |
| Python/test/test_phate.py | Adds tests validating out-of-sample projection for precomputed affinities (landmark + non-landmark) and preserves error for precomputed distances. |
| .gitignore | Ignores .venv/ virtual environments. |
Suppressed comments (3)
Python/phate/phate.py:986
- The precomputed-affinity out-of-sample path is gated on
TraditionalGraph, but the new helper_transform_precomputed_affinity()explicitly supports landmark graphs. IfLandmarkGraphis not aTraditionalGraph(seePHATE._parse_input()which treats them separately), this branch will never run forn_landmarkfits, andtransform()will fall back toextend_to_data(X)which expects a feature matrix rather than a query→train affinity matrix.
if (
self.knn_dist == "precomputed_affinity"
and isinstance(self.graph, graphtools.graphs.TraditionalGraph)
and self.graph.precomputed == "affinity"
):
Python/phate/phate.py:1036
_transform_precomputed_affinity()calls_ensure_embedded()with default arguments, sotransform(..., t_max=..., plot_optimal_t=..., ax=...)parameters are ignored in the precomputed-affinity out-of-sample path. This can change results whent='auto'and callers overridet_max/plotting behavior.
def _transform_precomputed_affinity(self, X):
"""Out-of-sample extension for a precomputed affinity graph
Given a query-to-train affinity matrix `X`, computes the PHATE
embedding of the query points as a transition-weighted combination
Python/phate/phate.py:991
- The ValueError message in the precomputed-graph branch says “precomputed distance matrix”, but this block can also be reached for other
graph.precomputedmodes (e.g., affinity whenknn_dist='precomputed'). The error should report the actualgraph.precomputedvalue so it’s accurate.
isinstance(self.graph, graphtools.graphs.TraditionalGraph)
and self.graph.precomputed is not None
):
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
977
to
981
| "Pre-fit PHATE should not be used to transform a " | ||
| "new data matrix. Please fit PHATE to the new" | ||
| " data by running 'fit' with the new data.", | ||
| RuntimeWarning, | ||
| ) |
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.
PHATE.transform() previously raised a ValueError for any precomputed graph, including knn_dist="precomputed_affinity". Unlike distances, a precomputed query-train affinity matrix is already a usable transition kernel, so no new kernel needs to be built.
transform() now recognizes this case and computes the out-of-sample embedding directly: row-normalize the query-train affinity (or, when the graph was fit with landmarks, first aggregate by landmark cluster and then row-normalize) and apply it to the fitted embedding.
Fixes #181