in graspologic/embed/base.py [0:0]
def transform(self, X): # type: ignore
"""
Obtain latent positions from an adjacency matrix or matrix of out-of-sample
vertices. For more details on transforming out-of-sample vertices, see the
:ref:`tutorials <embed_tutorials>`. For mathematical background, see [2].
Parameters
----------
X : array-like or tuple, original shape or (n_oos_vertices, n_vertices).
The original fitted matrix ("graph" in fit) or new out-of-sample data.
If ``X`` is the original fitted matrix, returns a matrix close to
``self.fit_transform(X)``.
If ``X`` is an out-of-sample matrix, n_oos_vertices is the number
of new vertices, and n_vertices is the number of vertices in the
original graph. If tuple, graph is directed and ``X[0]`` contains
edges from out-of-sample vertices to in-sample vertices.
Returns
-------
out : np.ndarray OR length 2 tuple of np.ndarray
Array of latent positions, shape (n_oos_vertices, n_components) or
(n_vertices, n_components). Transforms the fitted matrix if it was passed
in.
If ``X`` is an array or tuple containing adjacency vectors corresponding to
new nodes, returns the estimated latent positions for the new out-of-sample
adjacency vectors.
If undirected, returns array.
If directed, returns ``(X_out, X_in)``, where ``X_out`` contains
latent positions corresponding to nodes with edges from out-of-sample
vertices to in-sample vertices.
Notes
-----
If the matrix was diagonally augmented (e.g., ``self.diag_aug`` was True), ``fit``
followed by ``transform`` will produce a slightly different matrix than
``fit_transform``.
To get the original embedding, using ``fit_transform`` is recommended. In the
directed case, if A is the original in-sample adjacency matrix, the tuple
(A.T, A) will need to be passed to ``transform`` if you do not wish to use
``fit_transform``.
References
----------
.. [1] Sussman, D.L., Tang, M., Fishkind, D.E., Priebe, C.E. "A
Consistent Adjacency Spectral Embedding for Stochastic Blockmodel Graphs,"
Journal of the American Statistical Association, Vol. 107(499), 2012
.. [2] Levin, K., Roosta-Khorasani, F., Mahoney, M. W., & Priebe, C. E. (2018).
Out-of-sample extension of graph adjacency spectral embedding. PMLR: Proceedings
of Machine Learning Research, 80, 2975-2984
"""
# checks
check_is_fitted(self, "is_fitted_")
if isinstance(X, nx.classes.graph.Graph):
X = import_graph(X)
directed = self.latent_right_ is not None
# correct types?
if directed and not isinstance(X, tuple):
if X.shape[0] == X.shape[1]: # in case original matrix was passed
msg = """A square matrix A was passed to ``transform`` in the directed case.
If this was the original in-sample matrix, either use ``fit_transform``
or pass a tuple (A.T, A). If this was an out-of-sample matrix, directed
graphs require a tuple (X_out, X_in)."""
raise TypeError(msg)
else:
msg = "Directed graphs require a tuple (X_out, X_in) for out-of-sample transforms."
raise TypeError(msg)
if not directed and not isinstance(X, np.ndarray):
raise TypeError("Undirected graphs require array input")
# for oos prediction
inv_eigs = np.diag(1 / self.singular_values_)
self._pinv_left = self.latent_left_ @ inv_eigs
if self.latent_right_ is not None:
self._pinv_right = self.latent_right_ @ inv_eigs
# correct shape in y?
latent_rows = self.latent_left_.shape[0]
_X = X[0] if directed else X
X_cols = _X.shape[-1]
if _X.ndim > 2:
raise ValueError("out-of-sample vertex must be 1d or 2d")
if latent_rows != X_cols:
msg = "out-of-sample vertex must be shape (n_oos_vertices, n_vertices)"
raise ValueError(msg)
return self._compute_oos_prediction(X, directed)