matrix-hat 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- matrix_hat-0.1.0/.github/workflows/ci.yml +49 -0
- matrix_hat-0.1.0/.github/workflows/publish.yml +69 -0
- matrix_hat-0.1.0/.gitignore +31 -0
- matrix_hat-0.1.0/CHANGELOG.md +17 -0
- matrix_hat-0.1.0/CITATION.cff +22 -0
- matrix_hat-0.1.0/CONTRIBUTING.md +47 -0
- matrix_hat-0.1.0/LICENSE +21 -0
- matrix_hat-0.1.0/PKG-INFO +137 -0
- matrix_hat-0.1.0/PUBLISHING.md +127 -0
- matrix_hat-0.1.0/README.md +100 -0
- matrix_hat-0.1.0/docs/Makefile +14 -0
- matrix_hat-0.1.0/docs/_static/.gitkeep +0 -0
- matrix_hat-0.1.0/docs/conf.py +49 -0
- matrix_hat-0.1.0/docs/examples/index.rst +12 -0
- matrix_hat-0.1.0/docs/examples/synthetic.rst +24 -0
- matrix_hat-0.1.0/docs/index.rst +49 -0
- matrix_hat-0.1.0/docs/make.bat +16 -0
- matrix_hat-0.1.0/docs/reference/index.rst +9 -0
- matrix_hat-0.1.0/docs/reference/matrix_hat.rst +25 -0
- matrix_hat-0.1.0/docs/user/index.rst +10 -0
- matrix_hat-0.1.0/docs/user/installation.rst +33 -0
- matrix_hat-0.1.0/docs/user/leverage_diagnostics.rst +45 -0
- matrix_hat-0.1.0/docs/user/mathematical_background.rst +62 -0
- matrix_hat-0.1.0/docs/user/quickstart.rst +34 -0
- matrix_hat-0.1.0/examples/titanic_outliers/README.md +62 -0
- matrix_hat-0.1.0/examples/titanic_outliers/data/train.csv +892 -0
- matrix_hat-0.1.0/examples/titanic_outliers/matrix_hat_didatico.ipynb +1089 -0
- matrix_hat-0.1.0/examples/titanic_outliers/titanic_leverage.py +203 -0
- matrix_hat-0.1.0/pyproject.toml +57 -0
- matrix_hat-0.1.0/src/matrix_hat/__init__.py +29 -0
- matrix_hat-0.1.0/src/matrix_hat/_validation.py +34 -0
- matrix_hat-0.1.0/src/matrix_hat/core.py +354 -0
- matrix_hat-0.1.0/src/matrix_hat/py.typed +0 -0
- matrix_hat-0.1.0/tests/test_core.py +110 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main, master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install package with test extras
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade pip
|
|
28
|
+
pip install -e ".[test]"
|
|
29
|
+
|
|
30
|
+
- name: Run tests and doctests
|
|
31
|
+
run: pytest
|
|
32
|
+
|
|
33
|
+
docs:
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v4
|
|
37
|
+
|
|
38
|
+
- name: Set up Python
|
|
39
|
+
uses: actions/setup-python@v5
|
|
40
|
+
with:
|
|
41
|
+
python-version: "3.x"
|
|
42
|
+
|
|
43
|
+
- name: Install package with docs extras
|
|
44
|
+
run: |
|
|
45
|
+
python -m pip install --upgrade pip
|
|
46
|
+
pip install -e ".[docs]"
|
|
47
|
+
|
|
48
|
+
- name: Build documentation
|
|
49
|
+
run: sphinx-build -W -b html docs docs/_build/html
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
target:
|
|
7
|
+
description: "Where to publish"
|
|
8
|
+
required: true
|
|
9
|
+
type: choice
|
|
10
|
+
options:
|
|
11
|
+
- testpypi
|
|
12
|
+
- pypi
|
|
13
|
+
default: testpypi
|
|
14
|
+
release:
|
|
15
|
+
types: [published]
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
publish-testpypi:
|
|
22
|
+
if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
environment: testpypi
|
|
25
|
+
permissions:
|
|
26
|
+
id-token: write
|
|
27
|
+
contents: read
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
|
|
31
|
+
- uses: actions/setup-python@v5
|
|
32
|
+
with:
|
|
33
|
+
python-version: "3.x"
|
|
34
|
+
|
|
35
|
+
- name: Install build
|
|
36
|
+
run: python -m pip install --upgrade pip build
|
|
37
|
+
|
|
38
|
+
- name: Build package
|
|
39
|
+
run: python -m build
|
|
40
|
+
|
|
41
|
+
- name: Publish to TestPyPI
|
|
42
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
43
|
+
with:
|
|
44
|
+
repository-url: https://test.pypi.org/legacy/
|
|
45
|
+
|
|
46
|
+
publish-pypi:
|
|
47
|
+
if: >-
|
|
48
|
+
github.event_name == 'release' ||
|
|
49
|
+
(github.event_name == 'workflow_dispatch' && inputs.target == 'pypi')
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
environment: pypi
|
|
52
|
+
permissions:
|
|
53
|
+
id-token: write
|
|
54
|
+
contents: read
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/checkout@v4
|
|
57
|
+
|
|
58
|
+
- uses: actions/setup-python@v5
|
|
59
|
+
with:
|
|
60
|
+
python-version: "3.x"
|
|
61
|
+
|
|
62
|
+
- name: Install build
|
|
63
|
+
run: python -m pip install --upgrade pip build
|
|
64
|
+
|
|
65
|
+
- name: Build package
|
|
66
|
+
run: python -m build
|
|
67
|
+
|
|
68
|
+
- name: Publish to PyPI
|
|
69
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Byte-compiled / optimized
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.eggs/
|
|
11
|
+
|
|
12
|
+
# Testing / coverage
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
htmlcov/
|
|
16
|
+
.tox/
|
|
17
|
+
|
|
18
|
+
# Documentation
|
|
19
|
+
docs/_build/
|
|
20
|
+
docs/reference/generated/
|
|
21
|
+
|
|
22
|
+
# Virtual environments
|
|
23
|
+
.venv/
|
|
24
|
+
venv/
|
|
25
|
+
env/
|
|
26
|
+
|
|
27
|
+
# Editor / OS
|
|
28
|
+
.vscode/
|
|
29
|
+
.idea/
|
|
30
|
+
.cursor/
|
|
31
|
+
.DS_Store
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-07-19
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Public API: `leverage`, `hat_matrix`, `high_leverage_points`, `orthonormal_basis`, `effective_rank`.
|
|
13
|
+
- SVD-based, rank-revealing hat-matrix computations with optional intercept.
|
|
14
|
+
- NumPy-style documentation (Sphinx + numpydoc) and typed public API (`py.typed`).
|
|
15
|
+
- Example workflow under `examples/titanic_outliers/`.
|
|
16
|
+
|
|
17
|
+
[0.1.0]: https://github.com/aokienz/matrix-hat/releases/tag/v0.1.0
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it as below."
|
|
3
|
+
type: software
|
|
4
|
+
title: "matrix-hat: hat matrix and leverage diagnostics for linear regression"
|
|
5
|
+
version: 0.1.0
|
|
6
|
+
date-released: "2026-07-19"
|
|
7
|
+
license: MIT
|
|
8
|
+
repository-code: "https://github.com/aokienz/matrix-hat"
|
|
9
|
+
url: "https://github.com/aokienz/matrix-hat"
|
|
10
|
+
authors:
|
|
11
|
+
- family-names: Aoki
|
|
12
|
+
given-names: Enzo
|
|
13
|
+
email: enzoaoki02@gmail.com
|
|
14
|
+
abstract: >-
|
|
15
|
+
Small NumPy-only toolkit for the hat matrix and leverage diagnostics used
|
|
16
|
+
in linear regression, based on a rank-revealing SVD.
|
|
17
|
+
keywords:
|
|
18
|
+
- statistics
|
|
19
|
+
- regression
|
|
20
|
+
- hat-matrix
|
|
21
|
+
- leverage
|
|
22
|
+
- diagnostics
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for contributing to **matrix-hat**.
|
|
4
|
+
|
|
5
|
+
## Development setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/aokienz/matrix-hat.git
|
|
9
|
+
cd matrix-hat
|
|
10
|
+
python -m venv .venv
|
|
11
|
+
# Windows: .venv\Scripts\activate
|
|
12
|
+
# Unix: source .venv/bin/activate
|
|
13
|
+
pip install -e ".[dev]"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Tests and doctests
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pytest
|
|
20
|
+
pytest --doctest-modules src/matrix_hat
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Both are run in CI. Prefer stable doctest examples (e.g. `.round(2)`).
|
|
24
|
+
|
|
25
|
+
## Documentation
|
|
26
|
+
|
|
27
|
+
Build the Sphinx site with warnings treated as errors:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
sphinx-build -W -b html docs docs/_build/html
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
On Windows you can also run `docs\make.bat html`. Docstrings use **numpydoc**
|
|
34
|
+
(`Parameters`, `Returns`, `Raises`, `See Also`, `Notes`, `References`, `Examples`).
|
|
35
|
+
|
|
36
|
+
## Pull requests
|
|
37
|
+
|
|
38
|
+
1. Keep the public API small and NumPy-only unless discussed first.
|
|
39
|
+
2. Add or update tests for behaviour changes.
|
|
40
|
+
3. Update `CHANGELOG.md` under an `[Unreleased]` section when appropriate.
|
|
41
|
+
4. Keep `version` in `pyproject.toml` and `__version__` in
|
|
42
|
+
`src/matrix_hat/__init__.py` in sync when releasing.
|
|
43
|
+
|
|
44
|
+
## Code style
|
|
45
|
+
|
|
46
|
+
Match the existing style: type hints on public functions (`ArrayLike`,
|
|
47
|
+
`NDArray`), private helpers in `_validation.py`, and English docs/comments.
|
matrix_hat-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Enzo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: matrix-hat
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Hat matrix and leverage diagnostics for linear regression.
|
|
5
|
+
Project-URL: Homepage, https://github.com/aokienz/matrix-hat
|
|
6
|
+
Project-URL: Repository, https://github.com/aokienz/matrix-hat
|
|
7
|
+
Project-URL: Issues, https://github.com/aokienz/matrix-hat/issues
|
|
8
|
+
Author-email: Enzo Aoki <enzoaoki02@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: diagnostics,hat-matrix,influence,leverage,outliers,regression,statistics
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Requires-Dist: numpy>=1.21
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: numpydoc>=1.6; extra == 'dev'
|
|
27
|
+
Requires-Dist: pydata-sphinx-theme>=0.15; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: sphinx>=7.0; extra == 'dev'
|
|
30
|
+
Provides-Extra: docs
|
|
31
|
+
Requires-Dist: numpydoc>=1.6; extra == 'docs'
|
|
32
|
+
Requires-Dist: pydata-sphinx-theme>=0.15; extra == 'docs'
|
|
33
|
+
Requires-Dist: sphinx>=7.0; extra == 'docs'
|
|
34
|
+
Provides-Extra: test
|
|
35
|
+
Requires-Dist: pytest>=7.0; extra == 'test'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# matrix-hat
|
|
39
|
+
|
|
40
|
+
[](https://github.com/aokienz/matrix-hat/actions/workflows/ci.yml)
|
|
41
|
+
[](https://pypi.org/project/matrix-hat/)
|
|
42
|
+
[](https://pypi.org/project/matrix-hat/)
|
|
43
|
+
[](LICENSE)
|
|
44
|
+
|
|
45
|
+
Small, dependency-light toolkit for the **hat matrix** and **leverage**
|
|
46
|
+
diagnostics used in linear regression.
|
|
47
|
+
|
|
48
|
+
The hat matrix of a design matrix `X` is the orthogonal projection onto its
|
|
49
|
+
column space:
|
|
50
|
+
|
|
51
|
+
$$H = X (X^\top X)^{-1} X^\top$$
|
|
52
|
+
|
|
53
|
+
It earns its name because it turns observed responses into fitted values
|
|
54
|
+
("y-hat"): $\hat{y} = Hy$. Its diagonal entries $h_{ii}$ are the **leverages**,
|
|
55
|
+
which measure how far each observation sits from the centre of the predictor
|
|
56
|
+
space — a key tool for spotting influential points and outliers.
|
|
57
|
+
|
|
58
|
+
**Full documentation** (user guide, math background, API reference) lives in
|
|
59
|
+
[`docs/`](docs/). Build locally with `pip install -e ".[docs]"` then
|
|
60
|
+
`sphinx-build -W -b html docs docs/_build/html`.
|
|
61
|
+
|
|
62
|
+
## Why this package
|
|
63
|
+
|
|
64
|
+
- **Numerically stable.** Rank-revealing SVD instead of an explicit
|
|
65
|
+
`(XᵀX)⁻¹`, so it stays well-behaved on ill-conditioned or rank-deficient
|
|
66
|
+
designs.
|
|
67
|
+
- **Memory-aware.** `leverage()` returns just the diagonal without ever forming
|
|
68
|
+
the full `n × n` hat matrix.
|
|
69
|
+
- **Tiny footprint.** NumPy is the only runtime dependency.
|
|
70
|
+
|
|
71
|
+
## Installation
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install matrix-hat
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
From source (tests + docs):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pip install -e ".[dev]"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Quickstart
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import numpy as np
|
|
87
|
+
from matrix_hat import leverage, hat_matrix, high_leverage_points
|
|
88
|
+
|
|
89
|
+
X = np.array([[1.0], [2.0], [3.0], [4.0], [50.0]])
|
|
90
|
+
|
|
91
|
+
# Leverages (diagonal of the hat matrix), with an intercept column added.
|
|
92
|
+
h = leverage(X, add_intercept=True)
|
|
93
|
+
# array([0.267, 0.255, 0.245, 0.235, 0.998]) approx.
|
|
94
|
+
|
|
95
|
+
# Flag high-leverage observations (default rule of thumb: 2 * p / n).
|
|
96
|
+
high_leverage_points(X, add_intercept=True)
|
|
97
|
+
# array([4])
|
|
98
|
+
|
|
99
|
+
# The full projection matrix, when you actually need it.
|
|
100
|
+
H = hat_matrix(X, add_intercept=True)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## API
|
|
104
|
+
|
|
105
|
+
| Function | Description |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| `leverage(X, add_intercept=False)` | Leverages `h_ii` (diagonal of `H`) as a length-`n` vector. |
|
|
108
|
+
| `hat_matrix(X, add_intercept=False)` | The full `n × n` projection matrix `H`. |
|
|
109
|
+
| `high_leverage_points(X, threshold=None, factor=2.0)` | Indices of observations above a leverage cut-off. |
|
|
110
|
+
| `orthonormal_basis(X, add_intercept=False)` | Orthonormal basis `Q` for the column space (`H = Q Qᵀ`). |
|
|
111
|
+
| `effective_rank(X, add_intercept=False)` | Numerical rank of the design matrix. |
|
|
112
|
+
|
|
113
|
+
All functions accept a `tol` argument to control the singular-value cut-off
|
|
114
|
+
used for rank determination. See the Sphinx docs for full numpydoc reference
|
|
115
|
+
pages.
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
pip install -e ".[dev]"
|
|
121
|
+
pytest
|
|
122
|
+
sphinx-build -W -b html docs docs/_build/html
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
126
|
+
|
|
127
|
+
## Citation
|
|
128
|
+
|
|
129
|
+
If you use this package in research, see [CITATION.cff](CITATION.cff).
|
|
130
|
+
|
|
131
|
+
## Changelog
|
|
132
|
+
|
|
133
|
+
See [CHANGELOG.md](CHANGELOG.md).
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Publishing matrix-hat
|
|
2
|
+
|
|
3
|
+
Checklist for releasing `matrix-hat` to TestPyPI and PyPI via **Trusted Publishing** (GitHub Actions + OIDC). No API tokens in the repository.
|
|
4
|
+
|
|
5
|
+
**GitHub:** https://github.com/aokienz/matrix-hat
|
|
6
|
+
**PyPI name:** `matrix-hat`
|
|
7
|
+
**Import name:** `matrix_hat`
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## One-time setup
|
|
12
|
+
|
|
13
|
+
### 1. Accounts
|
|
14
|
+
|
|
15
|
+
- [ ] Account on [pypi.org](https://pypi.org) with **2FA** enabled
|
|
16
|
+
- [ ] Account on [test.pypi.org](https://test.pypi.org) with **2FA** enabled (separate from PyPI)
|
|
17
|
+
- [ ] Public GitHub repo `aokienz/matrix-hat` with this code on `main`
|
|
18
|
+
|
|
19
|
+
### 2. GitHub Environments
|
|
20
|
+
|
|
21
|
+
In the repo: **Settings → Environments**
|
|
22
|
+
|
|
23
|
+
- [ ] Create environment `testpypi`
|
|
24
|
+
- [ ] Create environment `pypi`
|
|
25
|
+
Optional: add protection rules (required reviewers, restrict to tags `v*`).
|
|
26
|
+
|
|
27
|
+
### 3. Trusted Publishers
|
|
28
|
+
|
|
29
|
+
**TestPyPI** → Account settings → Publishing → Add a new pending publisher:
|
|
30
|
+
|
|
31
|
+
| Field | Value |
|
|
32
|
+
|-------|--------|
|
|
33
|
+
| PyPI Project Name | `matrix-hat` |
|
|
34
|
+
| Owner | `aokienz` |
|
|
35
|
+
| Repository name | `matrix-hat` |
|
|
36
|
+
| Workflow name | `publish.yml` |
|
|
37
|
+
| Environment name | `testpypi` |
|
|
38
|
+
|
|
39
|
+
**PyPI** → same form with:
|
|
40
|
+
|
|
41
|
+
| Field | Value |
|
|
42
|
+
|-------|--------|
|
|
43
|
+
| PyPI Project Name | `matrix-hat` |
|
|
44
|
+
| Owner | `aokienz` |
|
|
45
|
+
| Repository name | `matrix-hat` |
|
|
46
|
+
| Workflow name | `publish.yml` |
|
|
47
|
+
| Environment name | `pypi` |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Local checks (before every release)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install -e ".[test]"
|
|
55
|
+
pytest
|
|
56
|
+
pip install build twine
|
|
57
|
+
Remove-Item -Recurse -Force dist -ErrorAction SilentlyContinue # PowerShell
|
|
58
|
+
python -m build
|
|
59
|
+
twine check dist/*
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Bump version in **both** `pyproject.toml` (`version`) and `src/matrix_hat/__init__.py` (`__version__`). Keep them identical.
|
|
63
|
+
|
|
64
|
+
Versions on PyPI are **immutable**. If `0.1.0` is wrong, ship `0.1.1`.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Publish to TestPyPI (dry run)
|
|
69
|
+
|
|
70
|
+
1. Push `main` with the workflows committed.
|
|
71
|
+
2. Confirm pending publisher on TestPyPI (step 3 above).
|
|
72
|
+
3. GitHub → **Actions** → **Publish** → **Run workflow** → target `testpypi`.
|
|
73
|
+
4. When green, install in a clean environment:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ matrix-hat==0.1.0
|
|
77
|
+
python -c "import matrix_hat; print(matrix_hat.__version__)"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
(`--extra-index-url` pulls NumPy from real PyPI.)
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Publish to PyPI
|
|
85
|
+
|
|
86
|
+
1. Confirm pending publisher on PyPI.
|
|
87
|
+
2. Preferred: create a **GitHub Release** with tag `v0.1.0` (this triggers the `publish-pypi` job).
|
|
88
|
+
3. Alternative: Actions → **Publish** → Run workflow → target `pypi`.
|
|
89
|
+
4. Verify:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pip install matrix-hat
|
|
93
|
+
python -c "from matrix_hat import leverage; print('ok')"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Project page: https://pypi.org/project/matrix-hat/
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Workflow map
|
|
101
|
+
|
|
102
|
+
| Trigger | Job | Index |
|
|
103
|
+
|---------|-----|--------|
|
|
104
|
+
| `workflow_dispatch` → `testpypi` | `publish-testpypi` | TestPyPI |
|
|
105
|
+
| `workflow_dispatch` → `pypi` | `publish-pypi` | PyPI |
|
|
106
|
+
| GitHub Release published | `publish-pypi` | PyPI |
|
|
107
|
+
|
|
108
|
+
CI (`ci.yml`) runs `pytest` on Python 3.9–3.13 for pushes/PRs to `main`/`master`.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## First push (if git is not set up yet)
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
git init
|
|
116
|
+
git add .
|
|
117
|
+
git commit -m "Initial release prep for matrix-hat 0.1.0"
|
|
118
|
+
git branch -M main
|
|
119
|
+
gh repo create matrix-hat --public --source=. --remote=origin --push
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Or create the empty repo on GitHub first, then:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
git remote add origin https://github.com/aokienz/matrix-hat.git
|
|
126
|
+
git push -u origin main
|
|
127
|
+
```
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# matrix-hat
|
|
2
|
+
|
|
3
|
+
[](https://github.com/aokienz/matrix-hat/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/matrix-hat/)
|
|
5
|
+
[](https://pypi.org/project/matrix-hat/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
Small, dependency-light toolkit for the **hat matrix** and **leverage**
|
|
9
|
+
diagnostics used in linear regression.
|
|
10
|
+
|
|
11
|
+
The hat matrix of a design matrix `X` is the orthogonal projection onto its
|
|
12
|
+
column space:
|
|
13
|
+
|
|
14
|
+
$$H = X (X^\top X)^{-1} X^\top$$
|
|
15
|
+
|
|
16
|
+
It earns its name because it turns observed responses into fitted values
|
|
17
|
+
("y-hat"): $\hat{y} = Hy$. Its diagonal entries $h_{ii}$ are the **leverages**,
|
|
18
|
+
which measure how far each observation sits from the centre of the predictor
|
|
19
|
+
space — a key tool for spotting influential points and outliers.
|
|
20
|
+
|
|
21
|
+
**Full documentation** (user guide, math background, API reference) lives in
|
|
22
|
+
[`docs/`](docs/). Build locally with `pip install -e ".[docs]"` then
|
|
23
|
+
`sphinx-build -W -b html docs docs/_build/html`.
|
|
24
|
+
|
|
25
|
+
## Why this package
|
|
26
|
+
|
|
27
|
+
- **Numerically stable.** Rank-revealing SVD instead of an explicit
|
|
28
|
+
`(XᵀX)⁻¹`, so it stays well-behaved on ill-conditioned or rank-deficient
|
|
29
|
+
designs.
|
|
30
|
+
- **Memory-aware.** `leverage()` returns just the diagonal without ever forming
|
|
31
|
+
the full `n × n` hat matrix.
|
|
32
|
+
- **Tiny footprint.** NumPy is the only runtime dependency.
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install matrix-hat
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
From source (tests + docs):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install -e ".[dev]"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quickstart
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import numpy as np
|
|
50
|
+
from matrix_hat import leverage, hat_matrix, high_leverage_points
|
|
51
|
+
|
|
52
|
+
X = np.array([[1.0], [2.0], [3.0], [4.0], [50.0]])
|
|
53
|
+
|
|
54
|
+
# Leverages (diagonal of the hat matrix), with an intercept column added.
|
|
55
|
+
h = leverage(X, add_intercept=True)
|
|
56
|
+
# array([0.267, 0.255, 0.245, 0.235, 0.998]) approx.
|
|
57
|
+
|
|
58
|
+
# Flag high-leverage observations (default rule of thumb: 2 * p / n).
|
|
59
|
+
high_leverage_points(X, add_intercept=True)
|
|
60
|
+
# array([4])
|
|
61
|
+
|
|
62
|
+
# The full projection matrix, when you actually need it.
|
|
63
|
+
H = hat_matrix(X, add_intercept=True)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## API
|
|
67
|
+
|
|
68
|
+
| Function | Description |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
| `leverage(X, add_intercept=False)` | Leverages `h_ii` (diagonal of `H`) as a length-`n` vector. |
|
|
71
|
+
| `hat_matrix(X, add_intercept=False)` | The full `n × n` projection matrix `H`. |
|
|
72
|
+
| `high_leverage_points(X, threshold=None, factor=2.0)` | Indices of observations above a leverage cut-off. |
|
|
73
|
+
| `orthonormal_basis(X, add_intercept=False)` | Orthonormal basis `Q` for the column space (`H = Q Qᵀ`). |
|
|
74
|
+
| `effective_rank(X, add_intercept=False)` | Numerical rank of the design matrix. |
|
|
75
|
+
|
|
76
|
+
All functions accept a `tol` argument to control the singular-value cut-off
|
|
77
|
+
used for rank determination. See the Sphinx docs for full numpydoc reference
|
|
78
|
+
pages.
|
|
79
|
+
|
|
80
|
+
## Development
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install -e ".[dev]"
|
|
84
|
+
pytest
|
|
85
|
+
sphinx-build -W -b html docs docs/_build/html
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
89
|
+
|
|
90
|
+
## Citation
|
|
91
|
+
|
|
92
|
+
If you use this package in research, see [CITATION.cff](CITATION.cff).
|
|
93
|
+
|
|
94
|
+
## Changelog
|
|
95
|
+
|
|
96
|
+
See [CHANGELOG.md](CHANGELOG.md).
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Minimal Makefile for Sphinx documentation
|
|
2
|
+
|
|
3
|
+
SPHINXOPTS ?= -W
|
|
4
|
+
SPHINXBUILD ?= sphinx-build
|
|
5
|
+
SOURCEDIR = .
|
|
6
|
+
BUILDDIR = _build
|
|
7
|
+
|
|
8
|
+
help:
|
|
9
|
+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
|
|
10
|
+
|
|
11
|
+
.PHONY: help Makefile
|
|
12
|
+
|
|
13
|
+
%: Makefile
|
|
14
|
+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
|
|
File without changes
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Sphinx configuration for matrix-hat documentation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
10
|
+
sys.path.insert(0, str(ROOT / "src"))
|
|
11
|
+
|
|
12
|
+
project = "matrix-hat"
|
|
13
|
+
author = "Enzo Aoki"
|
|
14
|
+
copyright = f"{datetime.now(timezone.utc).year}, {author}"
|
|
15
|
+
release = "0.1.0"
|
|
16
|
+
version = "0.1"
|
|
17
|
+
|
|
18
|
+
extensions = [
|
|
19
|
+
"sphinx.ext.autodoc",
|
|
20
|
+
"sphinx.ext.autosummary",
|
|
21
|
+
"sphinx.ext.intersphinx",
|
|
22
|
+
"sphinx.ext.mathjax",
|
|
23
|
+
"sphinx.ext.viewcode",
|
|
24
|
+
"numpydoc",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
autosummary_generate = True
|
|
28
|
+
autodoc_typehints = "none"
|
|
29
|
+
numpydoc_show_class_members = False
|
|
30
|
+
numpydoc_xref_param_type = True
|
|
31
|
+
|
|
32
|
+
templates_path = ["_templates"]
|
|
33
|
+
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|
34
|
+
|
|
35
|
+
html_theme = "pydata_sphinx_theme"
|
|
36
|
+
html_static_path = ["_static"]
|
|
37
|
+
html_title = "matrix-hat"
|
|
38
|
+
html_theme_options = {
|
|
39
|
+
"github_url": "https://github.com/aokienz/matrix-hat",
|
|
40
|
+
"show_toc_level": 2,
|
|
41
|
+
"navigation_with_keys": False,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
intersphinx_mapping = {
|
|
45
|
+
"python": ("https://docs.python.org/3", None),
|
|
46
|
+
"numpy": ("https://numpy.org/doc/stable/", None),
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
default_role = "py:obj"
|