cca_zoo.probabilistic¶
Probabilistic CCA via MCMC, black-box variational inference, or closed-form coordinate-ascent
variational Bayes. GFA has no extra dependencies; ProbabilisticCCA and
VariationalBayesCCA require pip install cca-zoo[probabilistic].
GFA ¶
GFA(
latent_dimensions: int = 1,
center: bool = True,
max_iter: int = 10000,
tol: float = 0.0001,
drop_k: bool = True,
num_posterior_samples: int = 1000,
random_state: int = 0,
)
Bases: PosteriorMeanTransformMixin, BaseModel
Group Factor Analysis: Bayesian CCA with per-view ARD.
Ported faithfully from the reference implementation, GFA() in the R
package CCAGFA <https://github.com/cran/CCAGFA>_ (Klami, Virtanen &
Kaski) — the update equations below are transliterated directly from
that source rather than re-derived. Fits a single shared latent
variable \(z\), but unlike
:class:~cca_zoo.probabilistic.ProbabilisticCCA and
:class:~cca_zoo.probabilistic.VariationalBayesCCA (which tie every
view to the same ARD precision per latent dimension), GFA gives each
view \(i\) its own ARD precision \(\alpha_{i,k}\) per latent dimension
\(k\):
"Shared" vs. "private" latent dimensions are therefore emergent, not a
fixed split of \(z\) into blocks: a dimension \(k\) ends up shared if
\(\alpha_{i,k}\) stays small (loadings retained) in several views at once,
and private to view \(i\) if \(\alpha_{i,k}\) shrinks toward zero loadings
in every other view. view_relevance_ (posterior mean of
\(\alpha_{i,k}\), shape (n_views, n_components_)) exposes this
directly.
Note also the noise model: \(\tau_i\) is a single scalar precision per view (homoscedastic — every feature in a view shares the same noise variance), not a per-feature diagonal like the other two classes — this matches the R package exactly, not an approximation.
Inference is closed-form coordinate-ascent mean-field variational Bayes
(conjugate throughout, so no black-box SVI is needed here unlike
:class:~cca_zoo.probabilistic.VariationalBayesCCA). latent_dimensions
is an upper bound: dimensions whose posterior mean squared value
falls below 1e-7 in every view are pruned during fitting
(drop_k=True, the R package's default), so the fitted number of
components, n_components_, can end up smaller than
latent_dimensions — every output array's last axis has size
n_components_, not latent_dimensions.
Note
This port omits the R package's optional orthogonal-rotation step
(opts$rotate, on by default in R) that speeds convergence and
helps escape poor local optima; it doesn't change the fitted model
class, only the optimization path, and is deferred to a follow-up
rather than risk porting it incorrectly without a reference R
run to check against.
Convergence is monitored via relative change in \(z\), sustained for
1000 consecutive iterations, rather than the R package's full
variational lower bound (which is guaranteed monotonically
non-decreasing under exact coordinate ascent — provably immune to
the issue below). This is a best-effort speed heuristic, not a
correctness guarantee: checking against a run with early stopping
disabled entirely caught this proxy dipping below tolerance for
700+ consecutive iterations in the middle of a slow ARD pruning
process (one dimension's decay temporarily dominating a
still-shrinking one), before rising again once that pruning
actually needed hundreds more iterations to finish — a patience
window can make this less likely but, unlike the true ELBO, can't
rule it out for an arbitrarily slow case. max_iter (default
10000) is the actual safety net: raise it if n_components_
looks larger than expected, rather than trusting early stopping
alone on a hard pruning problem.
References
Klami, A., Virtanen, S., & Kaski, S. (2013). "Bayesian Canonical Correlation Analysis." Journal of Machine Learning Research, 14, 965-1003. Virtanen, S., Klami, A., & Kaski, S. (2011). "Bayesian CCA via Group Sparsity." ICML.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
latent_dimensions
|
int
|
Upper bound on the number of latent components. Default is 1. |
1
|
center
|
bool
|
Whether to center each view before fitting. Default is True. |
True
|
max_iter
|
int
|
Maximum number of coordinate-ascent iterations, and the
actual safety net for correctness (see the class-level note on
early stopping being best-effort). Default is 10000 (the R
package defaults to 1e5, using it purely as a cap around
|
10000
|
tol
|
float
|
Relative Frobenius-norm change in the latent variable \(z\)
between iterations. Fitting stops once this stays below |
0.0001
|
drop_k
|
bool
|
Whether to prune latent dimensions with near-zero posterior
mean squared value across the whole run. Default is True
(matches the R package's |
True
|
num_posterior_samples
|
int
|
Number of samples drawn from the fitted
variational posterior to populate |
1000
|
random_state
|
int
|
Integer seed for reproducible initialization. Default is 0. |
0
|
Example
import numpy as np rng = np.random.default_rng(0) X1 = rng.standard_normal((50, 4)) X2 = rng.standard_normal((50, 3)) model = GFA(latent_dimensions=2, max_iter=50).fit([X1, X2])
Source code in cca_zoo/probabilistic/_gfa.py
fit ¶
Run coordinate-ascent variational Bayes to fit the GFA model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
views
|
list[ArrayLike]
|
List of arrays, each of shape (n_samples, n_features_i). All arrays must have the same number of rows. |
required |
y
|
None
|
Ignored. Present for scikit-learn API compatibility. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
self |
GFA
|
Fitted estimator. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If fewer than 2 views are provided. |
ValueError
|
If views have inconsistent numbers of samples. |
Source code in cca_zoo/probabilistic/_gfa.py
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | |
ProbabilisticCCA ¶
ProbabilisticCCA(
latent_dimensions: int = 1,
center: bool = True,
num_warmup: int = 500,
num_samples: int = 1000,
random_state: int = 0,
)
Bases: PosteriorMeanTransformMixin, BaseModel
Probabilistic Canonical Correlation Analysis via NUTS MCMC.
Fits a Bayesian latent variable model with the following generative process for \(V\) views:
MCMC sampling is performed with the No-U-Turn Sampler (NUTS) from
numpyro. After fitting, :meth:transform returns the posterior
mean of z conditioned on the observed views (computed analytically
using the posterior mean formula for linear Gaussian models).
This model has an exact rotational symmetry (\(z \to zR\), \(W_i \to W_i R\)
for any orthogonal \(R\) shared across views leaves the likelihood
unchanged), and different NUTS draws can settle on different rotations
along that ridge of equal density. Averaging un-aligned draws for a
point estimate is then biased toward zero (draws along different
rotations partially cancel), so fit aligns every draw's loadings
(and correspondingly, that draw's \(z\)) to a common reference via
generalized Procrustes analysis (see
:func:~cca_zoo.probabilistic._utils.align_posterior_rotation) before
computing weights_ or storing posterior_samples_.
The weights_ attribute is set to the (rotation-aligned) posterior
mean of each W_i matrix so that :class:~cca_zoo._base.BaseModel's
scoring utilities work without modification.
References
Bach, F. R. & Jordan, M. I. "A probabilistic interpretation of canonical correlation analysis." (2005). Wang, C. "Variational Bayesian approach to canonical correlation analysis." IEEE Transactions on Neural Networks 18.3 (2007).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
latent_dimensions
|
int
|
Dimensionality of the latent space. Default is 1. |
1
|
center
|
bool
|
Whether to center each view before fitting. Default is True. |
True
|
num_warmup
|
int
|
Number of NUTS warm-up (burn-in) steps. Default is 500. |
500
|
num_samples
|
int
|
Number of NUTS posterior samples to draw. Default is 1000. |
1000
|
random_state
|
int
|
Integer seed for JAX PRNG. Default is 0. |
0
|
Example
import numpy as np rng = np.random.default_rng(0) X1 = rng.standard_normal((50, 4)) X2 = rng.standard_normal((50, 3)) model = ProbabilisticCCA( ... latent_dimensions=2, num_warmup=10, num_samples=10 ... ).fit([X1, X2])
Source code in cca_zoo/probabilistic/_pcca.py
fit ¶
Run NUTS MCMC to infer posterior over model parameters and latents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
views
|
list[ArrayLike]
|
List of arrays, each of shape (n_samples, n_features_i). All arrays must have the same number of rows. |
required |
y
|
None
|
Ignored. Present for scikit-learn API compatibility. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
self |
ProbabilisticCCA
|
Fitted estimator. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If fewer than 2 views are provided. |
ValueError
|
If views have inconsistent numbers of samples. |
Source code in cca_zoo/probabilistic/_pcca.py
VariationalBayesCCA ¶
VariationalBayesCCA(
latent_dimensions: int = 1,
center: bool = True,
num_steps: int = 2000,
learning_rate: float = 0.01,
num_posterior_samples: int = 1000,
random_state: int = 0,
)
Bases: PosteriorMeanTransformMixin, BaseModel
Variational Bayesian CCA with automatic relevance determination.
Fits the same probabilistic CCA generative model as
:class:~cca_zoo.probabilistic.ProbabilisticCCA, extended with a
hierarchical automatic relevance determination (ARD) prior over the
columns of the loading matrices, shared across views:
Because \(\alpha_k\) is shared across every view's \(k\)-th loading column,
a latent dimension is only retained if some view finds it useful;
dimensions unsupported by the data are shrunk towards zero in every view
simultaneously. The posterior mean of \(\alpha_k\) (exposed as
ard_relevance_) is therefore a direct, per-dimension usefulness
score: large values indicate a dimension that has been shrunk away and
can be dropped, giving automatic latent-dimensionality selection instead
of a GridSearchCV sweep over latent_dimensions.
Inference uses mean-field stochastic variational inference (SVI) via
numpyro, rather than the closed-form conjugate coordinate-ascent updates
derived in Wang (2007) for this model: SVI reuses the exact same
numpyro generative-model machinery as
:class:~cca_zoo.probabilistic.ProbabilisticCCA, and (unlike a
hand-derived conjugate solver) extends unmodified to non-conjugate
variants of the model. It is a substantially cheaper alternative to that
class's full NUTS MCMC, at the cost of the mean-field independence
assumption between latent variables.
The weights_ attribute is set to the variational posterior mean of
each \(W_i\) matrix so that :class:~cca_zoo._base.BaseModel's scoring
utilities work without modification.
References
Bach, F. R. & Jordan, M. I. "A probabilistic interpretation of canonical correlation analysis." (2005). Wang, C. "Variational Bayesian approach to canonical correlation analysis." IEEE Transactions on Neural Networks 18.3 (2007).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
latent_dimensions
|
int
|
Dimensionality of the latent space. Default is 1.
Because of the ARD prior, this should be set generously (an
upper bound on the number of shared factors you expect); use
|
1
|
center
|
bool
|
Whether to center each view before fitting. Default is True. |
True
|
num_steps
|
int
|
Number of SVI gradient steps. Default is 2000. |
2000
|
learning_rate
|
float
|
Adam learning rate for SVI. Default is 1e-2. |
0.01
|
num_posterior_samples
|
int
|
Number of samples drawn from the fitted
variational posterior to populate |
1000
|
random_state
|
int
|
Integer seed for JAX PRNG. Default is 0. |
0
|
Example
import numpy as np rng = np.random.default_rng(0) X1 = rng.standard_normal((50, 4)) X2 = rng.standard_normal((50, 3)) model = VariationalBayesCCA( ... latent_dimensions=2, num_steps=50 ... ).fit([X1, X2])
Source code in cca_zoo/probabilistic/_vbcca.py
fit ¶
Run mean-field SVI to infer an approximate posterior.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
views
|
list[ArrayLike]
|
List of arrays, each of shape (n_samples, n_features_i). All arrays must have the same number of rows. |
required |
y
|
None
|
Ignored. Present for scikit-learn API compatibility. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
self |
VariationalBayesCCA
|
Fitted estimator. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If fewer than 2 views are provided. |
ValueError
|
If views have inconsistent numbers of samples. |