@@ -31,6 +31,53 @@ class MultispatiPCA:
31
31
:math:`H=1/(2n)*X^t(W+W^t)X` where `X` is matrix of `n` observations :math:`\\ times`
32
32
`d` features, and `W` is a matrix of the connectivity between observations.
33
33
34
+ Parameters
35
+ ----------
36
+ n_components : int or tuple[int, int], optional
37
+ Number of components to keep.
38
+ If None, will keep all components (only supported for non-sparse `X`).
39
+ If an int, it will keep the top `n_components`.
40
+ If a tuple, it will keep the top and bottom `n_components` respectively.
41
+ connectivity : scipy.sparse.sparray or scipy.sparse.spmatrix
42
+ Matrix of row-wise neighbor definitions i.e. c\ :sub:`ij` is the connectivity of
43
+ i :math:`\\ to` j. The matrix does not have to be symmetric. It can be a
44
+ binary adjacency matrix or a matrix of connectivities in which case
45
+ c\ :sub:`ij` should be larger if i and j are close.
46
+ A distance matrix should be transformed to connectivities by e.g.
47
+ calculating :math:`1-d/d_{max}` beforehand.
48
+
49
+ Raises
50
+ ------
51
+ ValueError
52
+ If connectivity is not a square matrix.
53
+ ZeroDivisionError
54
+ If one of the observations has no neighbors.
55
+
56
+ Attributes
57
+ ----------
58
+ components_ : numpy.ndarray
59
+ The estimated components: Array of shape `(n_components, n_features)`.
60
+
61
+ variance_ : numpy.ndarray
62
+ The estimated variance part of the eigenvalues. Array of shape `(n_components,)`.
63
+
64
+ moransI_ : numpy.ndarray
65
+ The estimated Moran's I part of the eigenvalues. Array of shape `(n_components,)`.
66
+
67
+ eigenvalues_ : numpy.ndarray
68
+ The eigenvalues corresponding to each of the selected components. Array of shape
69
+ `(n_components,)`.
70
+
71
+ n_components_ : int
72
+ The estimated number of components.
73
+
74
+ n_samples_ : int
75
+ Number of samples in the training data.
76
+
77
+ n_features_in_ : int
78
+ Number of features seen during :term:`fit`.
79
+
80
+
34
81
References
35
82
----------
36
83
`Dray, Stéphane, Sonia Saïd, and Françis Débias. "Spatial ordination of vegetation
@@ -47,29 +94,6 @@ def __init__(
47
94
* ,
48
95
connectivity : sparray | spmatrix ,
49
96
):
50
- """
51
- Parameters
52
- ----------
53
-
54
- n_components : int or tuple[int, int], optional
55
- Number of components to keep.
56
- If None, will keep all components (only supported for non-sparse `X`).
57
- If an int, it will keep the top `n_components`.
58
- If a tuple, it will keep the top and bottom `n_components` respectively.
59
- connectivity : scipy.sparse.sparray or scipy.sparse.spmatrix
60
- Matrix of row-wise neighbor definitions i.e. c\ :sub:`ij` is the connectivity of
61
- i :math:`\\ to` j. The matrix does not have to be symmetric. It can be a
62
- binary adjacency matrix or a matrix of connectivities in which case
63
- c\ :sub:`ij` should be larger if i and j are close.
64
- A distance matrix should be transformed to connectivities by e.g.
65
- calculating :math:`1-d/d_{max}` beforehand.
66
- Raises
67
- ------
68
- ValueError
69
- If connectivity is not a square matrix.
70
- ZeroDivisionError
71
- If one of the observations has no neighbors.
72
- """
73
97
self ._fitted = False
74
98
W = csr_array (connectivity )
75
99
if W .shape [0 ] != W .shape [1 ]:
@@ -247,7 +271,10 @@ def transform(self, X: _X) -> np.ndarray:
247
271
self ._not_fitted ()
248
272
249
273
X = scale (X , with_mean = not issparse (X ))
250
- return X @ self .components_
274
+ X_t = X @ self .components_
275
+ self .variance_ , self .moransI_ = self ._variance_moransI_decomposition (X_t )
276
+
277
+ return X_t
251
278
252
279
def fit_transform (self , X : _X ) -> np .ndarray :
253
280
"""
@@ -291,36 +318,17 @@ def transform_spatial_lag(self, X: _X) -> np.ndarray:
291
318
def _spatial_lag (self , X : np .ndarray ) -> np .ndarray :
292
319
return self .W @ X
293
320
294
- def variance_moransI_decomposition (self , X : _X ) -> tuple [np .ndarray , np .ndarray ]:
295
- """
296
- Calculate the decomposition of the variance and Moran's I for `n_components`.
297
-
298
- Parameters
299
- ----------
300
- X : numpy.ndarray or scipy.sparse.csr_array or scipy.sparse.csc_array
301
- Array of observations x features.
302
-
303
- Returns
304
- -------
305
- tuple[numpy.ndarray, numpy.ndarray]
306
- Variance and Moran's I.
307
-
308
- Raises
309
- ------
310
- ValueError
311
- If instance has not been fitted.
312
- """
313
- if not self ._fitted :
314
- self ._not_fitted ()
315
- transformed = self .transform (X )
316
- lag = self ._spatial_lag (transformed )
321
+ def _variance_moransI_decomposition (
322
+ self , X_t : np .ndarray
323
+ ) -> tuple [np .ndarray , np .ndarray ]:
324
+ lag = self ._spatial_lag (X_t )
317
325
318
326
# vector of row_Weights from dudi.PCA
319
- # (we only use default row_weights i.e. 1/n anyways )
320
- w = 1 / X .shape [0 ]
327
+ # (we only use default row_weights i.e. 1/n)
328
+ w = 1 / X_t .shape [0 ]
321
329
322
- variance = np .sum (transformed * transformed * w , axis = 0 )
323
- moran = np .sum (transformed * lag * w , axis = 0 ) / variance
330
+ variance = np .sum (X_t * X_t * w , axis = 0 )
331
+ moran = np .sum (X_t * lag * w , axis = 0 ) / variance
324
332
325
333
return variance , moran
326
334
0 commit comments