{"id":28148137,"url":"https://github.com/finite-sample/pyppur","last_synced_at":"2026-03-11T15:32:26.647Z","repository":{"id":286036172,"uuid":"960151616","full_name":"finite-sample/pyppur","owner":"finite-sample","description":"pyppur: Python Projection Pursuit Unsupervised (Dimension) Reduction To Min. Reconstruction Loss or DIstance DIstortion","archived":false,"fork":false,"pushed_at":"2025-12-28T02:58:12.000Z","size":402,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-30T06:57:23.022Z","etag":null,"topics":["projection-pursuit","reconstruction-loss"],"latest_commit_sha":null,"homepage":"https://finite-sample.github.io/pyppur/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/finite-sample.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-04T00:11:31.000Z","updated_at":"2025-12-28T02:58:16.000Z","dependencies_parsed_at":"2025-12-14T13:03:56.809Z","dependency_job_id":null,"html_url":"https://github.com/finite-sample/pyppur","commit_stats":null,"previous_names":["gojiplus/pypurr","finite-sample/pyppur","gojiplus/pyppur"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/finite-sample/pyppur","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/finite-sample%2Fpyppur","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/finite-sample%2Fpyppur/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/finite-sample%2Fpyppur/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/finite-sample%2Fpyppur/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/finite-sample","download_url":"https://codeload.github.com/finite-sample/pyppur/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/finite-sample%2Fpyppur/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30386029,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-11T14:10:17.325Z","status":"ssl_error","status_checked_at":"2026-03-11T14:09:37.934Z","response_time":84,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["projection-pursuit","reconstruction-loss"],"created_at":"2025-05-15T00:24:05.808Z","updated_at":"2026-03-11T15:32:26.617Z","avatar_url":"https://github.com/finite-sample.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"### 🪈 pyppur: **P**ython **P**rojection **P**ursuit **U**nsupervised **R**eduction\n\n[![PyPI](https://img.shields.io/pypi/v/pyppur.svg)](https://pypi.org/project/pyppur/)\n[![Python](https://img.shields.io/badge/dynamic/toml?url=https://raw.githubusercontent.com/finite-sample/pyppur/main/pyproject.toml\u0026query=$.project.requires-python\u0026label=Python)](https://github.com/finite-sample/pyppur)\n[![PyPI Downloads](https://static.pepy.tech/badge/pyppur)](https://pepy.tech/projects/pyppur)\n[![Documentation](https://img.shields.io/badge/docs-latest-brightgreen.svg)](https://finite-sample.github.io/pyppur/)\n[![CI](https://github.com/finite-sample/pyppur/workflows/CI/badge.svg)](https://github.com/finite-sample/pyppur/actions/workflows/ci.yml)\n\n## Overview\n\n`pyppur` is a Python package that implements projection pursuit methods for dimensionality reduction. Unlike traditional methods such as PCA, `pyppur` focuses on finding interesting non-linear projections by minimizing either reconstruction loss or distance distortion.\n\n## Installation\n\n```bash\npip install pyppur\n```\n\n## Features\n\n- Two optimization objectives:\n  - **Distance Distortion**: Preserves pairwise distances between data points\n  - **Reconstruction**: Minimizes reconstruction error using ridge functions\n- Multiple initialization strategies (PCA-based and random)\n- Full scikit-learn compatible API\n- Supports standardization and custom weighting\n\n## Usage\n\n### Basic Example\n\n```python\nimport numpy as np\nfrom pyppur import ProjectionPursuit, Objective\nfrom sklearn.datasets import load_digits\n\n# Load data\ndigits = load_digits()\nX = digits.data\ny = digits.target\n\n# Projection pursuit with distance distortion\npp_dist = ProjectionPursuit(\n    n_components=2,\n    objective=Objective.DISTANCE_DISTORTION,\n    alpha=1.5,  # Steepness of the ridge function\n    n_init=3,   # Number of random initializations\n    verbose=True\n)\n\n# Fit and transform\nX_transformed = pp_dist.fit_transform(X)\n\n# Projection pursuit with reconstruction loss (tied weights)\npp_recon_tied = ProjectionPursuit(\n    n_components=2,\n    objective=Objective.RECONSTRUCTION,\n    alpha=1.0,\n    tied_weights=True\n)\n\n# Projection pursuit with reconstruction loss (free decoder)\npp_recon_free = ProjectionPursuit(\n    n_components=2,\n    objective=Objective.RECONSTRUCTION,\n    alpha=1.0,\n    tied_weights=False,\n    l2_reg=0.01\n)\n\n# Fit and transform\nX_transformed_recon_tied = pp_recon_tied.fit_transform(X)\nX_transformed_recon_free = pp_recon_free.fit_transform(X)\n\n# Evaluate the methods\ndist_metrics = pp_dist.evaluate(X, y)\nrecon_tied_metrics = pp_recon_tied.evaluate(X, y)\nrecon_free_metrics = pp_recon_free.evaluate(X, y)\n\nprint(\"Distance distortion method:\")\nprint(f\"  Trustworthiness: {dist_metrics['trustworthiness']:.4f}\")\nprint(f\"  Silhouette: {dist_metrics['silhouette']:.4f}\")\nprint(f\"  Distance distortion: {dist_metrics['distance_distortion']:.4f}\")\nprint(f\"  Reconstruction error: {dist_metrics['reconstruction_error']:.4f}\")\n\nprint(\"\\nReconstruction method (tied weights):\")\nprint(f\"  Trustworthiness: {recon_tied_metrics['trustworthiness']:.4f}\")\nprint(f\"  Silhouette: {recon_tied_metrics['silhouette']:.4f}\")\nprint(f\"  Distance distortion: {recon_tied_metrics['distance_distortion']:.4f}\")\nprint(f\"  Reconstruction error: {recon_tied_metrics['reconstruction_error']:.4f}\")\n\nprint(\"\\nReconstruction method (free decoder):\")\nprint(f\"  Trustworthiness: {recon_free_metrics['trustworthiness']:.4f}\")\nprint(f\"  Silhouette: {recon_free_metrics['silhouette']:.4f}\")\nprint(f\"  Distance distortion: {recon_free_metrics['distance_distortion']:.4f}\")\nprint(f\"  Reconstruction error: {recon_free_metrics['reconstruction_error']:.4f}\")\n```\n\n\n## API Reference\n\nThe main class in `pyppur` is `ProjectionPursuit`, which provides the following methods:\n\n- `fit(X)`: Fit the model to data\n- `transform(X)`: Apply dimensionality reduction to new data\n- `fit_transform(X)`: Fit the model and transform data\n- `reconstruct(X)`: Reconstruct data from projections\n- `reconstruction_error(X)`: Compute reconstruction error\n- `distance_distortion(X)`: Compute distance distortion\n- `compute_trustworthiness(X, n_neighbors)`: Measure how well local structure is preserved\n- `compute_silhouette(X, labels)`: Measure how well clusters are separated\n- `evaluate(X, labels, n_neighbors)`: Compute all evaluation metrics at once\n\n## Theory\n\nProjection pursuit finds interesting low-dimensional projections of multivariate data. When used for dimensionality reduction, it aims to optimize an \"interestingness\" index which can be:\n\n1. **Distance Distortion**: Minimizes the difference between pairwise distances in original and projected spaces (optionally with nonlinearity)\n2. **Reconstruction Error**: Minimizes the error when reconstructing the data using ridge functions\n\n### Mathematical Formulations\n\n#### Tied-Weights Ridge Autoencoder (Default)\n```\nZ = g(X A^T)\nX̂ = Z A\n```\n\n#### Free Decoder Ridge Autoencoder (Available with tied_weights=False)\n```\nZ = g(X A^T)  \nX̂ = Z B\n```\n\nWhere:\n- `X` is the input data matrix (n_samples × n_features)\n- `A` are the encoder projection directions (n_components × n_features)\n- `B` are the decoder weights (n_components × n_features, when untied)\n- `g(z) = tanh(α * z)` is the ridge function with steepness parameter α\n- `Z` is the projected data (n_samples × n_components)\n- `X̂` is the reconstructed data\n\n#### Distance Distortion Options\n- **With nonlinearity**: Compares distances between original space and `g(X A^T)`\n- **Without nonlinearity**: Compares distances between original space and linear projections `X A^T`\n\n## Requirements\n\n- Python 3.10+\n- NumPy (\u003e=1.20.0)\n- SciPy (\u003e=1.7.0)  \n- scikit-learn (\u003e=1.0.0)\n- matplotlib (\u003e=3.3.0)\n\n## License\n\nMIT\n\n## Citation\n\nIf you use `pyppur` in your research, please cite it as:\n\n```\n@software{pyppur,\n  author = {Gaurav Sood},\n  title = {pyppur: Python Projection Pursuit Unsupervised Reduction},\n  url = {https://github.com/gojiplus/pyppur},\n  version = {0.2.0},\n  year = {2025},\n}\n```\n\n## 🔗 Adjacent Repositories\n\n- [gojiplus/get-weather-data](https://github.com/gojiplus/get-weather-data) — Get weather data for a list of zip codes for a range of dates\n- [gojiplus/text-as-data](https://github.com/gojiplus/text-as-data) — Pipeline for Analyzing Text Data: Acquire, Preprocess, Analyze\n- [gojiplus/calibre](https://github.com/gojiplus/calibre) — Advanced Calibration Models\n- [gojiplus/skiplist_join](https://github.com/gojiplus/skiplist_join)\n- [gojiplus/rmcp](https://github.com/gojiplus/rmcp) — R MCP Server\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffinite-sample%2Fpyppur","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffinite-sample%2Fpyppur","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffinite-sample%2Fpyppur/lists"}