Metadata-Version: 2.4
Name: logisticpca
Version: 0.4.0
Summary: Projection-based logistic principal component analysis for binary data
Author-email: Reda Abouzaid <azaidr00@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/azaidr/logisticpca
Project-URL: Repository, https://github.com/azaidr/logisticpca
Project-URL: Issues, https://github.com/azaidr/logisticpca/issues
Keywords: logistic PCA,binary data,dimensionality reduction,health informatics,diagnosis codes
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Healthcare Industry
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.23
Requires-Dist: scipy>=1.9
Requires-Dist: scikit-learn>=1.2
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Dynamic: license-file

# logisticpca

`logisticpca` provides projection-based Logistic Principal Component Analysis for binary matrices, together with a probabilistic PCA helper for continuous data.

Version 0.4.0 is a breaking methodological correction. Versions 0.3.x implemented a free-score logistic SVD while exposing it as `LogisticPCA`. Version 0.4.0 implements the projection formulation of Landgraf and Lee (2020), with a single orthonormal loading basis and a closed-form projection for complete new rows.

## Installation

```bash
pip install logisticpca
```

For development:

```bash
git clone https://github.com/azaidr/logisticpca.git
cd logisticpca
python -m pip install -e ".[dev]"
pytest
```

## Basic use

```python
import numpy as np
from logisticpca import LogisticPCA

rng = np.random.default_rng(42)
X = rng.binomial(1, 0.15, size=(500, 100))

model = LogisticPCA(
    n_components=3,
    m=4.0,
    max_iter=1000,
    tol=1e-5,
)

scores = model.fit_transform(X)
probabilities = model.predict_proba(X)

print(scores.shape)                    # (500, 3)
print(model.converged_)
print(model.termination_reason_)
print(model.average_deviance_)
print(model.deviance_explained_)
```

For complete rows, `fit_transform(X)` and `fit(X).transform(X)` return the same score matrix by construction.

## Selecting the component count and saturation constant

The default selector uses row folds plus entrywise masking. The model is fitted on training rows. For each held-out row, the score is estimated from observed entries only, and deviance is evaluated only on the withheld entries.

```python
from logisticpca import CVLogisticPCA

selector = CVLogisticPCA(
    component_grid=[1, 2, 3, 4, 5],
    m_grid=[2.0, 4.0, 6.0],
    cv=5,
    validation="entrywise",
    validation_fraction=0.20,
    score_method="bernoulli",
    random_state=42,
)

scores = selector.fit_transform(X)
print(selector.best_n_components_)
print(selector.best_m_)
print(selector.cv_results_)
```

`validation="row_reconstruction"` is also available. That mode uses the full held-out row to compute its projection score and then reconstructs the same row. It measures complete-row reconstruction, not entrywise predictive performance, and it can favor larger ranks.

## Partially observed rows

```python
X_partial = X[:10].astype(float)
observed_mask = np.ones_like(X_partial, dtype=bool)
observed_mask[:, :20] = False
X_partial[:, :20] = np.nan

scores_partial = model.transform_partial(
    X_partial,
    observed_mask=observed_mask,
    method="bernoulli",
    ridge=1e-6,
)
```

The default partial-score method maximizes a ridge-penalized Bernoulli likelihood using observed entries only. A finite-saturated-parameter least-squares projection is available with `method="least_squares"`.

## Constant columns

All-zero and all-one training columns are excluded from the loading subspace. With `main_effects=True`, they are represented as finite intercept-only features with intercepts `-m` and `+m`, respectively. Their loading rows are zero. This prevents constant columns from driving Bernoulli intercepts toward infinity.

If every column is constant, fitting raises an error because no nonconstant subspace exists.

## Model definition

Let

```text
Q = 2X - 1
Eta = mQ
Theta = 1 mu' + (Eta - 1 mu') U U'
```

where `U` has orthonormal columns. The model minimizes Bernoulli deviance using a majorization-minimization update based on the global one-quarter curvature bound of the logistic loss.

The `m` parameter is a finite approximation to the saturated natural parameters. Version 0.4.0 requires `m > 0`. The unstable unconstrained Newton update for `m` is not implemented. Use a prespecified value or select among a bounded grid with `CVLogisticPCA`.

## Interpretation of reported deviance

`loss_history_` contains average Bernoulli deviance per matrix entry, including the initialization. `reconstruction_deviance_` is the total fitted deviance. `deviance_explained_` is calculated over nonconstant features because empirically constant features have zero null deviance.

## Computational scope

The current implementation requires a dense matrix and forms feature-by-feature Gram matrices. Memory use scales quadratically and eigendecomposition scales cubically in the number of nonconstant features. Filter unsupported or nearly empty features before fitting very wide diagnosis-code or EHR matrices.

## Probabilistic PCA

The package retains the separate EM-based probabilistic PCA helper:

```python
from logisticpca import prob_pca

W, latent_mean, feature_means, sigma2 = prob_pca(
    continuous_X,
    num_components=3,
    return_sigma=True,
    random_state=42,
)
```

## Migration from 0.3.x

Results from 0.4.0 are not numerically comparable with 0.3.x because the estimator changed from free-score logistic SVD to projection Logistic PCA. See [MIGRATION.md](MIGRATION.md). The historical 0.3.5 tag should remain available for exact reproduction of analyses that used the earlier implementation.

## Reference

Landgraf, A. J., and Lee, Y. (2020). Dimensionality reduction for binary data through the projection of natural parameters. *Journal of Multivariate Analysis*, 180, 104668. https://doi.org/10.1016/j.jmva.2020.104668

## License

MIT License. See [LICENSE](LICENSE).
