geom-nmf
Geometric non-negative matrix factorization (GeomNMF) via maximum-volume simplex fitting.
GeomNMF assumes a nonnegative data matrix follows a simplex mixing model
Y ≈ W H, W ≥ 0, H ≥ 0, H 1 = 1
and estimates the source profiles H (endmembers) as the vertices of the maximum-volume
(K−1)-simplex inscribed in the convex hull of the row-normalized data. It then recovers the
mixing weights W and a source attribution matrix Φ giving the share of each feature
attributable to each source. Typical applications include source apportionment of
multi-pollutant air quality data and spectral unmixing.
Getting Started
Installation
Install the latest version directly from GitHub:
pip install git+https://github.com/jinbora0720/geom-nmf.git
With optional plotting (matplotlib) and progress-bar (tqdm) support:
pip install "geom-nmf[all] @ git+https://github.com/jinbora0720/geom-nmf.git"
| Extra | Enables |
|---|---|
plot |
barplot_Phi (installs matplotlib) |
progress |
tqdm progress bar for the max-volume search (verbose=True) |
all |
both |
Install from a specific branch or tag:
pip install git+https://github.com/jinbora0720/geom-nmf.git@<branch-name-or-tag>
Quick example
import numpy as np
from geom_nmf import GeomNMF, barplot_Phi, permute_to_reference
rng = np.random.default_rng(0)
K, J, N = 3, 6, 1000
H_true = rng.dirichlet(np.ones(J), size=K) # (K, J) source profiles
W_true = rng.dirichlet(0.5 * np.ones(K), size=N) # (N, K) mixing proportions
Y = rng.lognormal(size=(N, 1)) * (W_true @ H_true) # (N, J) nonnegative data
result = GeomNMF(Y, K=3)
result.H_star # (K, J) estimated source profiles, rows sum to 1
result.W_tilde # (N, K) source contributions on the original scale of Y
result.mu_tilde # (K,) mean contribution per source
result.Phi # (K, J) share of each feature attributable to each source
result.fit_diagnostics["intrinsic_rank"] # should be K - 1 for noise-free data
# sources are identified up to permutation; align with a reference if you have one
H_hat, mu_hat, Phi_hat, order = permute_to_reference(H_true, result.H_star, result.mu_tilde, result.Phi)
barplot_Phi(Phi_hat, feature_labels=["PM1", "PM2.5", "PM10", "CO", "NO2", "O3"])
Y can be a NumPy array, a pandas DataFrame, or any 2-D array-like. A runnable version is in
examples/quickstart.py.
Public API
| Function / class | Purpose |
|---|---|
GeomNMF |
Full pipeline; returns a GeomNMFResult named tuple |
nfindr |
Standalone N-FINDR endmember extraction |
log_simplex_volume |
Log-volume of the simplex spanned by K points |
estimate_weights |
Recover simplex weights W given Y and H |
compute_Phi |
Source attribution matrix from mean weights and H |
permute_to_reference |
Align estimated sources to a reference ordering (Hungarian) |
barplot_Phi |
Grouped bar plot of Φ, optionally with bootstrap error bars |
Choosing options
candidate_method="exact"(default) uses convex-hull vertices and is globally optimal, but the number of hull vertices grows quickly for noisy, high-dimensional data.candidate_method="random"uses extremes along random projections; cap the pool withn_candidates.prune=Trueclusters candidates before the exhaustive search. It can discard the true extremes, so pair it withrefine_greedy=True, which runs N-FINDR swaps on the full data and keeps the result only if it increases the simplex volume.- A
RuntimeWarningis raised if the exhaustive search would exceed 50 million subsets.
Contributing
We welcome contributions! If you'd like to fix a bug, add a feature, or improve documentation, follow the steps below. Don't worry if you're new to this — it's a straightforward process once you've done it a couple of times.
This project uses Poetry to manage dependencies and virtual environments.
1. Fork the repository
A "fork" is your own personal copy of the project on GitHub. To create one, click the Fork button in the top-right corner of the geom-nmf repository page.
2. Clone your fork
Download your fork to your local machine:
git clone https://github.com/<your-github-username>/geom-nmf.git
cd geom-nmf
3. Install Poetry
If you don't already have Poetry installed, choose the instructions for your operating system below.
macOS
The recommended way on macOS is via Homebrew. If you don't have Homebrew installed, install it first:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Then install Poetry:
brew install poetry
Linux / Windows (WSL)
curl -sSL https://install.python-poetry.org | python3 -
Then follow any instructions it prints to add Poetry to your PATH.
Verify the installation
poetry --version
4. Install dependencies
This installs both the main dependencies and the development dependencies (e.g. pytest, sphinx) into an isolated virtual environment managed by Poetry:
poetry install
To also install the optional coverage or documentation tools:
poetry install --with coverage
poetry install --with docs
You only need to run this once (and again whenever dependencies change).
To activate the virtual environment (Poetry ≥ 2.0):
eval $(poetry env activate)
On Poetry 1.x, use poetry shell instead.
Your prompt will change to indicate you're inside the environment. To exit when you're done:
exit
Alternatively, prefix any command with poetry run to run it inside the environment without activating it:
poetry run pytest tests/
5. Create a branch
Never make changes directly on main. Instead, create a new branch with a short descriptive name:
git checkout -b my-feature-branch
6. Make your changes
Edit files, write code, fix bugs — whatever your contribution involves. Keep your changes focused on one thing per branch.
7. Run the tests
Before submitting, make sure all tests pass:
poetry run pytest tests/
If you've added new functionality, add a corresponding test in the tests/ directory.
Common flags:
| Flag | Description |
|---|---|
-v |
Verbose output — shows each test name and pass/fail status |
-q |
Quiet output — minimal output, just a summary |
-x |
Stop after the first failure |
-s |
Disable output capture — allows print() statements to show in terminal |
-k "expression" |
Run only tests whose names match the expression (e.g. -k "test_fit") |
--tb=short |
Show a shortened traceback on failures (short, long, no, line) |
--cov=geom_nmf |
Report test coverage for the package (requires pytest-cov) |
Examples:
# Run all tests verbosely
pytest -v tests/
# Stop on first failure with full traceback
pytest -x --tb=long tests/
# Run only tests matching a keyword
pytest -v -k "test_fit" tests/
# Run with coverage report
pytest --cov=geom_nmf --cov-report=term-missing tests/
8. Commit and push your changes
Stage and commit your changes with a clear message describing what you did:
git add <file(s) you changed>
git commit -m "Brief description of your change"
git push origin my-feature-branch
9. Open a Pull Request
Go to your fork on GitHub. You should see a prompt to open a Pull Request — click it. Fill in a short description of what your changes do and why. A maintainer will review your PR and may leave comments or request changes before merging.
Tips
- Keep pull requests small and focused — one feature or fix per PR is much easier to review
- Check that your branch is up to date with
mainbefore opening a PR:git fetch origin git rebase origin/main
- To add a new dependency:
poetry add <package>(orpoetry add --group dev <package>for dev-only) - If you're unsure about a change, open an issue first to discuss it before writing code
Building Documentation
The documentation is built with Sphinx from the NumPy-style docstrings in the source code.
poetry install --with docs
poetry run make -C docs html
Then open docs/_build/html/index.html in your browser. The build treats warnings as errors
(-W), so broken references or malformed docstrings will fail the build.
Building a distribution
poetry build # writes dist/geom_nmf-<version>.tar.gz and .whl
© 2026 Bora Jin. Released under the MIT License.
Metadata
Release files for geom-nmf 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| geom_nmf-0.1.0.tar.gz | 25.6 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| geom_nmf-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 51.7 kB
Release files / geom_nmf-0.1.0.tar.gz
| Download URL | geom_nmf-0.1.0.tar.gz |
|---|---|
| Size | 25.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e169eb13d6da2aba876b29e97b60ea71ae46f5a52ba6c890227d2495c5513646
|
|
BLAKE2b-256 checksum How to use checksums |
d6d6afe162889d8081fba018cd2eb1f7f771dc36b6ee6c5b8cd65056a9569967
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logRelease files / geom_nmf-0.1.0-py3-none-any.whl
| Download URL | geom_nmf-0.1.0-py3-none-any.whl |
|---|---|
| Size | 26.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
11142eec531f59822d8a40ea5d4c5deb0f133d395afc39cbcfea34203220f81a
|
|
BLAKE2b-256 checksum How to use checksums |
f9f1c035e183c8b85ab1c33b027c4223eda9a45ce10c8c243a98e46cb4b54f1b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logSecurity for geom-nmf 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for geom_nmf-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.