Skip to main content

An easy-to-use package for Positive Matrix Factorization (PMF) analysis of environmental data.

Project description

Easy PMF

PyPI version Python versions License: MIT

CI/CD Documentation Publish

Easy PMF is a comprehensive Python package for Positive Matrix Factorization (PMF) analysis, designed specifically for environmental data analysis such as air quality source apportionment. It provides an easy-to-use interface similar to EPA's PMF software with built-in visualization capabilities.

:warning: This project is in the early stages of development and may not yet be suitable for production use.

:warning: A LLM (Large Language Model) is being used to assist with development and documentation; much of the content was vibe coded without much oversight.

✨ Features

  • Simple API: Easy-to-use interface similar to scikit-learn
  • Comprehensive Visualizations: EPA PMF-style plots and heatmaps
  • Multiple Dataset Support: Built-in support for various environmental datasets
  • Robust Error Handling: Input validation and convergence checking
  • Flexible Data Input: Support for CSV, TXT, and Excel files
  • Interactive Analysis: Command-line tools for quick analysis
  • Well Documented: Extensive documentation with examples

🚀 Quick Start

Installation

pip install easy-pmf

Basic Usage

import pandas as pd
from easy_pmf import PMF

# Load your concentration and uncertainty data
concentrations = pd.read_csv("concentrations.csv", index_col=0)
uncertainties = pd.read_csv("uncertainties.csv", index_col=0)

# Initialize PMF with 5 factors
pmf = PMF(n_components=5, random_state=42)

# Fit the model
pmf.fit(concentrations, uncertainties)

# Access results
factor_contributions = pmf.contributions_  # Time series of factor contributions
factor_profiles = pmf.profiles_            # Chemical profiles of each factor

# Check model performance
q_value = pmf.score(concentrations, uncertainties)
print(f"Model Q-value: {q_value:.2f}")
print(f"Converged: {pmf.converged_}")
print(f"Iterations: {pmf.n_iter_}")

Command Line Interface

# Analyze a single dataset interactively
easy-pmf

# Or use the analysis scripts directly
python quick_analysis.py

📊 Included Example Datasets

The package comes with three real-world datasets:

  • Baton Rouge: Air quality data (307 samples × 41 species)
  • St. Louis: Environmental monitoring data (418 samples × 13 species)
  • Baltimore: PM2.5 composition data (657 samples × 26 species)

🎯 Use Cases

  • Air Quality Analysis: Source apportionment of particulate matter
  • Environmental Monitoring: Identifying pollution sources
  • Research: Academic studies requiring PMF analysis
  • Regulatory Compliance: EPA-style PMF analysis for reporting

📈 Visualization Capabilities

Easy PMF automatically generates comprehensive visualizations:

  • Factor Profiles: Chemical signatures of each source
  • Factor Contributions: Time series showing source strength
  • Correlation Matrices: Relationships between factors
  • EPA-style Plots: Publication-ready visualizations
  • Summary Dashboards: Quick overview of results

📚 Documentation

PMF Class Parameters

  • n_components (int): Number of factors to extract
  • max_iter (int, default=1000): Maximum iterations
  • tol (float, default=1e-4): Convergence tolerance
  • random_state (int, optional): Random seed for reproducibility

Methods

  • fit(X, U=None): Fit PMF model to data
  • transform(X, U=None): Apply fitted model to new data
  • score(X, U=None): Calculate Q-value for goodness of fit

Data Format Requirements

  • Concentrations: Rows = time points, Columns = chemical species
  • Uncertainties: Same format as concentrations (optional)
  • Index: Date/time information
  • Values: Non-negative concentrations

🛠️ Advanced Usage

Custom Analysis Pipeline

from easy_pmf import PMF
import matplotlib.pyplot as plt

# Load and preprocess data
concentrations = pd.read_csv("data.csv", index_col=0)
uncertainties = pd.read_csv("uncertainties.csv", index_col=0)

# Remove low-signal species
concentrations = concentrations.loc[:, (concentrations > 0).any(axis=0)]
uncertainties = uncertainties[concentrations.columns]

# Try different numbers of factors
for n_factors in range(3, 8):
    pmf = PMF(n_components=n_factors, random_state=42)
    pmf.fit(concentrations, uncertainties)
    q_value = pmf.score(concentrations, uncertainties)
    print(f"Factors: {n_factors}, Q-value: {q_value:.2f}")

# Analyze best model
best_pmf = PMF(n_components=5, random_state=42)
best_pmf.fit(concentrations, uncertainties)

# Custom visualization
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))

# Plot factor profiles
best_pmf.profiles_.T.plot(kind='bar', ax=ax1)
ax1.set_title('Factor Profiles')
ax1.set_xlabel('Chemical Species')

# Plot contributions over time
best_pmf.contributions_.plot(ax=ax2)
ax2.set_title('Factor Contributions Over Time')
ax2.set_ylabel('Contribution')

plt.tight_layout()
plt.show()

Batch Processing Multiple Datasets

import os
from easy_pmf import PMF

datasets = {
    "site1": {"conc": "site1_conc.csv", "unc": "site1_unc.csv"},
    "site2": {"conc": "site2_conc.csv", "unc": "site2_unc.csv"},
}

results = {}
for site, files in datasets.items():
    print(f"Analyzing {site}...")

    conc = pd.read_csv(files["conc"], index_col=0)
    unc = pd.read_csv(files["unc"], index_col=0)

    pmf = PMF(n_components=5, random_state=42)
    pmf.fit(conc, unc)

    results[site] = {
        "contributions": pmf.contributions_,
        "profiles": pmf.profiles_,
        "q_value": pmf.score(conc, unc),
        "converged": pmf.converged_
    }

    print(f"  Q-value: {results[site]['q_value']:.2f}")
    print(f"  Converged: {results[site]['converged']}")

🔧 Development & Infrastructure

CI/CD Pipeline

This project features a comprehensive CI/CD infrastructure:

  • ✅ Automated Testing: Matrix testing across Python 3.9-3.12 on Ubuntu, macOS, and Windows
  • ✅ Code Quality: Automated linting, formatting, and type checking with pre-commit hooks
  • ✅ Security Scanning: Dependency vulnerability scanning with Bandit
  • ✅ Documentation: Automatic deployment to GitHub Pages
  • ✅ Package Publishing: Automated PyPI publishing on releases
  • ✅ Dependency Management: Weekly dependency updates and maintenance

Code Quality Standards

  • Type Safety: Full type annotation coverage with mypy validation
  • Code Style: Enforced with Ruff (linting and formatting)
  • Testing: Comprehensive test suite with pytest
  • Documentation: Auto-generated docs with MkDocs Material
  • Pre-commit Hooks: Quality checks run on every commit using uv

🤝 Contributing

🤝 Contributing

We welcome contributions! Please see our Contributing Guidelines for details on:

  • Development setup with uv and pre-commit hooks
  • Code quality standards and automated checks
  • Testing requirements and CI/CD infrastructure
  • Documentation guidelines and examples
  • Pull request process and review requirements

Quick Start for Contributors

# Fork and clone the repository
git clone https://github.com/YOUR_USERNAME/easy-pmf.git
cd easy-pmf

# Set up development environment
uv sync --all-extras
uv run pre-commit install

# Make changes and test
uv run pytest
uv run pre-commit run --all-files

Development Setup

git clone https://github.com/gerritjandebruin/easy-pmf.git
cd easy-pmf

# Install uv (modern Python package manager)
# On Windows: https://docs.astral.sh/uv/getting-started/installation/
# On macOS/Linux: curl -LsSf https://astral.sh/uv/install.sh | sh

# Create development environment and install dependencies
uv sync --all-extras

# Install pre-commit hooks for code quality
uv run pre-commit install

# Run tests to verify setup
uv run pytest

# Run type checking
uv run mypy .

# Run code formatting and linting
uv run ruff check --fix
uv run ruff format

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • EPA PMF software for inspiration
  • Marloes van Os for first contributions and ideas

📞 Support


Easy PMF - Making positive matrix factorization accessible to everyone! 🌍

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

easy_pmf-0.1.0.tar.gz (200.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

easy_pmf-0.1.0-py3-none-any.whl (197.7 kB view details)

Uploaded Python 3

File details

Details for the file easy_pmf-0.1.0.tar.gz.

File metadata

  • Download URL: easy_pmf-0.1.0.tar.gz
  • Upload date:
  • Size: 200.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for easy_pmf-0.1.0.tar.gz
Algorithm Hash digest
SHA256 338f6c61d761d63d178906c556995c88fd5df8bf64290740950f0a70b74f15ac
MD5 a5fa451bad5c5749c3f8974af0659a42
BLAKE2b-256 77193f7fa649484dcdf2bf052e097ec907dcad766baf9811b947ec05de8c9dba

See more details on using hashes here.

Provenance

The following attestation bundles were made for easy_pmf-0.1.0.tar.gz:

Publisher: publish.yml on gerritjandebruin/easy-pmf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file easy_pmf-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: easy_pmf-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 197.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for easy_pmf-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 010e423f0d1ebd5f3edc2631307ab496de77f6615fa6da4b861e24250f3ab89e
MD5 ad6514b5922cf02c519440821b041e43
BLAKE2b-256 4c00b914b505866f5dc2999c5116ccaa282c864f382c3e3bc40b8435544c8b78

See more details on using hashes here.

Provenance

The following attestation bundles were made for easy_pmf-0.1.0-py3-none-any.whl:

Publisher: publish.yml on gerritjandebruin/easy-pmf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page