modelmatrix 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.
- modelmatrix-0.1.0/.github/workflows/build_docs.yml +86 -0
- modelmatrix-0.1.0/.github/workflows/build_test.yml +83 -0
- modelmatrix-0.1.0/.gitignore +7 -0
- modelmatrix-0.1.0/CHANGELOG.md +29 -0
- modelmatrix-0.1.0/LICENSE +27 -0
- modelmatrix-0.1.0/PKG-INFO +72 -0
- modelmatrix-0.1.0/README.md +39 -0
- modelmatrix-0.1.0/docs/.gitignore +2 -0
- modelmatrix-0.1.0/docs/PCA.md +97 -0
- modelmatrix-0.1.0/docs/anova.md +103 -0
- modelmatrix-0.1.0/docs/api/ModelSpec.rst +7 -0
- modelmatrix-0.1.0/docs/api/conf.py +41 -0
- modelmatrix-0.1.0/docs/api/index.rst +12 -0
- modelmatrix-0.1.0/docs/api/terms.rst +29 -0
- modelmatrix-0.1.0/docs/api/transforms.rst +6 -0
- modelmatrix-0.1.0/docs/comparison.md +452 -0
- modelmatrix-0.1.0/docs/index.md +24 -0
- modelmatrix-0.1.0/docs/myst.yml +28 -0
- modelmatrix-0.1.0/docs/poly.md +118 -0
- modelmatrix-0.1.0/docs/spec.md +315 -0
- modelmatrix-0.1.0/docs/splines.md +116 -0
- modelmatrix-0.1.0/modelmatrix/__init__.py +26 -0
- modelmatrix-0.1.0/modelmatrix/_version.py +24 -0
- modelmatrix-0.1.0/modelmatrix/columns.py +324 -0
- modelmatrix-0.1.0/modelmatrix/model_spec.py +1710 -0
- modelmatrix-0.1.0/modelmatrix/transforms.py +695 -0
- modelmatrix-0.1.0/modelmatrix.egg-info/PKG-INFO +72 -0
- modelmatrix-0.1.0/modelmatrix.egg-info/SOURCES.txt +41 -0
- modelmatrix-0.1.0/modelmatrix.egg-info/dependency_links.txt +1 -0
- modelmatrix-0.1.0/modelmatrix.egg-info/requires.txt +17 -0
- modelmatrix-0.1.0/modelmatrix.egg-info/scm_file_list.json +37 -0
- modelmatrix-0.1.0/modelmatrix.egg-info/scm_version.json +8 -0
- modelmatrix-0.1.0/modelmatrix.egg-info/top_level.txt +1 -0
- modelmatrix-0.1.0/pyproject.toml +59 -0
- modelmatrix-0.1.0/setup.cfg +4 -0
- modelmatrix-0.1.0/tests/_datasets.py +21 -0
- modelmatrix-0.1.0/tests/data/Carseats.csv +401 -0
- modelmatrix-0.1.0/tests/data/Wage.csv +3001 -0
- modelmatrix-0.1.0/tests/test_boolean_columns.py +27 -0
- modelmatrix-0.1.0/tests/test_columns.py +29 -0
- modelmatrix-0.1.0/tests/test_model_matrix.py +370 -0
- modelmatrix-0.1.0/tests/test_model_spec.py +287 -0
- modelmatrix-0.1.0/tests/test_model_spec_hard.py +1124 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# This builds and deploys the modelmatrix docs
|
|
2
|
+
|
|
3
|
+
name: Build docs
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs: null
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v7
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0 # setuptools_scm takes the version from the tags
|
|
18
|
+
|
|
19
|
+
- uses: actions/setup-python@v7
|
|
20
|
+
with:
|
|
21
|
+
python-version: '3.12'
|
|
22
|
+
cache: 'pip'
|
|
23
|
+
|
|
24
|
+
# Jupyter Book 2 (mystmd) runs on Node
|
|
25
|
+
- uses: actions/setup-node@v7
|
|
26
|
+
with:
|
|
27
|
+
node-version: '24'
|
|
28
|
+
|
|
29
|
+
# Install
|
|
30
|
+
- name: Install dependencies
|
|
31
|
+
run: |
|
|
32
|
+
sudo apt-get update && sudo apt-get install -y r-base
|
|
33
|
+
pip install .[doc]
|
|
34
|
+
# the data of the pages (ISLP's load_data, without its dependencies)
|
|
35
|
+
pip install --no-deps ISLP
|
|
36
|
+
|
|
37
|
+
# The narrative docs: Jupyter Book 2, notebooks executed.
|
|
38
|
+
# BASE_URL: the site is served from https://<owner>.github.io/modelmatrix/
|
|
39
|
+
- name: Make book
|
|
40
|
+
env:
|
|
41
|
+
BASE_URL: /${{ github.event.repository.name }}
|
|
42
|
+
run: |
|
|
43
|
+
cd docs
|
|
44
|
+
jupyter-book build --html --execute --ci
|
|
45
|
+
test -f _build/html/index.html
|
|
46
|
+
|
|
47
|
+
# The API reference: Sphinx autodoc, into api/ next to the book
|
|
48
|
+
- name: Make API reference
|
|
49
|
+
run: |
|
|
50
|
+
sphinx-build -b html docs/api docs/_build/html/api
|
|
51
|
+
test -f docs/_build/html/api/index.html
|
|
52
|
+
|
|
53
|
+
# Store the output
|
|
54
|
+
- name: Upload docs
|
|
55
|
+
uses: actions/upload-artifact@v7
|
|
56
|
+
with:
|
|
57
|
+
name: modelmatrix_docs
|
|
58
|
+
path: docs/_build/html
|
|
59
|
+
retention-days: 5
|
|
60
|
+
if-no-files-found: error
|
|
61
|
+
|
|
62
|
+
deploy:
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
needs: build
|
|
65
|
+
|
|
66
|
+
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
|
|
67
|
+
permissions:
|
|
68
|
+
pages: write # to deploy to Pages
|
|
69
|
+
id-token: write # to verify the deployment originates from an appropriate source
|
|
70
|
+
|
|
71
|
+
environment:
|
|
72
|
+
name: github-pages
|
|
73
|
+
url: ${{steps.deployment.outputs.page_url}}
|
|
74
|
+
|
|
75
|
+
steps:
|
|
76
|
+
- uses: actions/download-artifact@v8
|
|
77
|
+
with:
|
|
78
|
+
name: modelmatrix_docs
|
|
79
|
+
path: .
|
|
80
|
+
- uses: actions/configure-pages@v6
|
|
81
|
+
|
|
82
|
+
- uses: actions/upload-pages-artifact@v5
|
|
83
|
+
with:
|
|
84
|
+
path: .
|
|
85
|
+
- id: deployment
|
|
86
|
+
uses: actions/deploy-pages@v5
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
name: Build and test
|
|
2
|
+
|
|
3
|
+
# Linux (Python 3.12) on pull requests, into any branch; on pushes to main
|
|
4
|
+
# (merges) and by hand, macOS and Windows (3.12) and Linux at the oldest and
|
|
5
|
+
# newest Pythons (3.11, 3.14), and the sdist and wheel build. The package is
|
|
6
|
+
# pure Python, so this is enough. Changes only to the docs or Markdown files
|
|
7
|
+
# do not run the tests.
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches: [main]
|
|
11
|
+
paths-ignore: ['docs/**', '**.md']
|
|
12
|
+
pull_request:
|
|
13
|
+
paths-ignore: ['docs/**', '**.md']
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
# a new push to a branch cancels the run still going for it
|
|
17
|
+
concurrency:
|
|
18
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
19
|
+
cancel-in-progress: true
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
build:
|
|
23
|
+
name: build (${{ matrix.os }}, ${{ matrix.python-version }})
|
|
24
|
+
runs-on: ${{ matrix.os }}
|
|
25
|
+
strategy:
|
|
26
|
+
fail-fast: false
|
|
27
|
+
matrix:
|
|
28
|
+
include: >-
|
|
29
|
+
${{ fromJSON(github.event_name == 'pull_request' && '[
|
|
30
|
+
{"os": "ubuntu-latest", "python-version": "3.12"}
|
|
31
|
+
]' || '[
|
|
32
|
+
{"os": "windows-latest", "python-version": "3.12"},
|
|
33
|
+
{"os": "macos-latest", "python-version": "3.12"},
|
|
34
|
+
{"os": "ubuntu-latest", "python-version": "3.11"},
|
|
35
|
+
{"os": "ubuntu-latest", "python-version": "3.14"}
|
|
36
|
+
]') }}
|
|
37
|
+
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v7
|
|
40
|
+
with:
|
|
41
|
+
fetch-depth: 0 # setuptools_scm takes the version from the tags
|
|
42
|
+
|
|
43
|
+
- name: Install uv
|
|
44
|
+
uses: astral-sh/setup-uv@v10.3.0
|
|
45
|
+
with:
|
|
46
|
+
enable-cache: true
|
|
47
|
+
cache-dependency-glob: "**/pyproject.toml"
|
|
48
|
+
|
|
49
|
+
- name: Set up Python
|
|
50
|
+
run: uv python install ${{ matrix.python-version }}
|
|
51
|
+
|
|
52
|
+
- name: Install Project
|
|
53
|
+
run: uv sync --dev --python ${{ matrix.python-version }}
|
|
54
|
+
|
|
55
|
+
- name: Lint with flake8
|
|
56
|
+
run: |
|
|
57
|
+
uv run flake8 modelmatrix --count --select=E9,F63,F7,F82,W605 --show-source --statistics
|
|
58
|
+
uv run flake8 modelmatrix --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
|
59
|
+
|
|
60
|
+
- name: Test with pytest
|
|
61
|
+
timeout-minutes: 10
|
|
62
|
+
shell: bash
|
|
63
|
+
run: |
|
|
64
|
+
args=()
|
|
65
|
+
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
66
|
+
args+=(--cov=modelmatrix --cov-report=term-missing)
|
|
67
|
+
fi
|
|
68
|
+
uv run pytest "${args[@]}"
|
|
69
|
+
|
|
70
|
+
build-dist:
|
|
71
|
+
# the sdist and wheel build, and the wheel installs and imports
|
|
72
|
+
if: github.event_name != 'pull_request'
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
steps:
|
|
75
|
+
- uses: actions/checkout@v7
|
|
76
|
+
with:
|
|
77
|
+
fetch-depth: 0
|
|
78
|
+
- uses: astral-sh/setup-uv@v10.3.0
|
|
79
|
+
- run: uv build
|
|
80
|
+
- run: |
|
|
81
|
+
uv venv -p 3.12 /tmp/venv
|
|
82
|
+
uv pip install -p /tmp/venv dist/*.whl
|
|
83
|
+
/tmp/venv/bin/python -c "import modelmatrix; print(modelmatrix.__version__)"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.1.0 (2026-10-26)
|
|
6
|
+
|
|
7
|
+
`ModelSpec`, from [ISLP](https://github.com/intro-stat-learning/ISLP) 0.6.0,
|
|
8
|
+
as its own package, with the history of its files. ISLP 0.7 depends on it,
|
|
9
|
+
and `from ISLP.models import ModelSpec` keeps working there.
|
|
10
|
+
|
|
11
|
+
### Changes from ISLP 0.6.0
|
|
12
|
+
|
|
13
|
+
- **`intercept` defaults to `False`:** pass `intercept=True` for a column
|
|
14
|
+
of ones named `'intercept'`, as statsmodels' models (`OLS`, `GLM`, ...)
|
|
15
|
+
need. Most scikit-learn estimators fit the intercept themselves.
|
|
16
|
+
- No `FutureWarning` of the move.
|
|
17
|
+
- Import from `modelmatrix` (`ModelSpec`, `Column`, `Feature`, `Contrast`,
|
|
18
|
+
`Ordinal`, `poly`, `ns`, `bs`, `pca`, `contrast`, `ordinal`,
|
|
19
|
+
`derived_feature`, `build_columns`); the transforms are in
|
|
20
|
+
`modelmatrix.transforms`.
|
|
21
|
+
- The docs: the guide to `ModelSpec`, the pages on polynomials, splines,
|
|
22
|
+
PCA and ANOVA, and the comparison with `ColumnTransformer`, patsy and
|
|
23
|
+
formulaic, from ISLP's docs, as a Jupyter Book 2 site (as glmstar's),
|
|
24
|
+
with a Sphinx API reference.
|
|
25
|
+
|
|
26
|
+
For the changes up to ISLP 0.6.0, see
|
|
27
|
+
[ISLP's changelog](https://github.com/intro-stat-learning/ISLP/blob/main/CHANGELOG.md).
|
|
28
|
+
|
|
29
|
+
Requires Python 3.11 or later.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Redistribution and use in source and binary forms, with or without
|
|
2
|
+
modification, are permitted provided that the following conditions are
|
|
3
|
+
met:
|
|
4
|
+
|
|
5
|
+
(1) Redistributions of source code must retain the above copyright
|
|
6
|
+
notice, this list of conditions and the following disclaimer.
|
|
7
|
+
|
|
8
|
+
(2) Redistributions in binary form must reproduce the above copyright
|
|
9
|
+
notice, this list of conditions and the following disclaimer in
|
|
10
|
+
the documentation and/or other materials provided with the
|
|
11
|
+
distribution.
|
|
12
|
+
|
|
13
|
+
(3)The name of the author may not be used to
|
|
14
|
+
endorse or promote products derived from this software without
|
|
15
|
+
specific prior written permission.
|
|
16
|
+
|
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
18
|
+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
19
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
+
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
21
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
22
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
23
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
24
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
25
|
+
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
26
|
+
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
27
|
+
POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: modelmatrix
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Model matrices from tabular data, as scikit-learn transformers
|
|
5
|
+
Author-email: Jonathan Taylor <jonathan.taylor@stanford.edu>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/intro-stat-learning/modelmatrix
|
|
8
|
+
Project-URL: Documentation, https://intro-stat-learning.github.io/modelmatrix
|
|
9
|
+
Project-URL: Changelog, https://github.com/intro-stat-learning/modelmatrix/blob/main/CHANGELOG.md
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering
|
|
13
|
+
Requires-Python: >=3.11
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: numpy>=1.7.1
|
|
17
|
+
Requires-Dist: pandas>=1.5
|
|
18
|
+
Requires-Dist: scipy>=0.9
|
|
19
|
+
Requires-Dist: scikit-learn>=1.2
|
|
20
|
+
Requires-Dist: narwhals>=1.26
|
|
21
|
+
Requires-Dist: joblib
|
|
22
|
+
Provides-Extra: doc
|
|
23
|
+
Requires-Dist: jupyter-book<3,>=2; extra == "doc"
|
|
24
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
25
|
+
Requires-Dist: sphinx-book-theme; extra == "doc"
|
|
26
|
+
Requires-Dist: statsmodels; extra == "doc"
|
|
27
|
+
Requires-Dist: patsy; extra == "doc"
|
|
28
|
+
Requires-Dist: formulaic; extra == "doc"
|
|
29
|
+
Requires-Dist: polars; extra == "doc"
|
|
30
|
+
Requires-Dist: rpy2; extra == "doc"
|
|
31
|
+
Requires-Dist: jupytext; extra == "doc"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# modelmatrix
|
|
35
|
+
|
|
36
|
+
Model matrices from tabular data, as scikit-learn transformers.
|
|
37
|
+
|
|
38
|
+
`ModelSpec` builds a design matrix from a `pd.DataFrame` (or a polars or
|
|
39
|
+
pyarrow frame, or an `np.ndarray`) from a list of terms: columns,
|
|
40
|
+
categorical encodings, polynomials, splines, principal components and
|
|
41
|
+
their interactions. It is a scikit-learn transformer, so it goes in a
|
|
42
|
+
`Pipeline`, is cloned and cross-validated, and the parameters of its
|
|
43
|
+
terms are tuned with `GridSearchCV`.
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from modelmatrix import ModelSpec, ns, poly
|
|
47
|
+
from sklearn.linear_model import LinearRegression
|
|
48
|
+
from sklearn.model_selection import GridSearchCV
|
|
49
|
+
from sklearn.pipeline import make_pipeline
|
|
50
|
+
|
|
51
|
+
spec = ModelSpec([ns('age', df=4), poly('year', 2), 'education',
|
|
52
|
+
('age', 'education')])
|
|
53
|
+
X = spec.fit_transform(Wage)
|
|
54
|
+
|
|
55
|
+
pipe = make_pipeline(spec, LinearRegression())
|
|
56
|
+
grid = GridSearchCV(pipe, {'modelspec__terms__0__df': [2, 4, 8]})
|
|
57
|
+
grid.fit(Wage, Wage['wage'])
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`ModelSpec` was written for the labs of
|
|
61
|
+
[An Introduction to Statistical Learning with Python](https://www.statlearning.com),
|
|
62
|
+
and `from ISLP.models import ModelSpec` still works there.
|
|
63
|
+
|
|
64
|
+
Documentation: https://intro-stat-learning.github.io/modelmatrix
|
|
65
|
+
|
|
66
|
+
## Install
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
pip install modelmatrix
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Requires Python 3.11 or later. BSD licensed.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# modelmatrix
|
|
2
|
+
|
|
3
|
+
Model matrices from tabular data, as scikit-learn transformers.
|
|
4
|
+
|
|
5
|
+
`ModelSpec` builds a design matrix from a `pd.DataFrame` (or a polars or
|
|
6
|
+
pyarrow frame, or an `np.ndarray`) from a list of terms: columns,
|
|
7
|
+
categorical encodings, polynomials, splines, principal components and
|
|
8
|
+
their interactions. It is a scikit-learn transformer, so it goes in a
|
|
9
|
+
`Pipeline`, is cloned and cross-validated, and the parameters of its
|
|
10
|
+
terms are tuned with `GridSearchCV`.
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
from modelmatrix import ModelSpec, ns, poly
|
|
14
|
+
from sklearn.linear_model import LinearRegression
|
|
15
|
+
from sklearn.model_selection import GridSearchCV
|
|
16
|
+
from sklearn.pipeline import make_pipeline
|
|
17
|
+
|
|
18
|
+
spec = ModelSpec([ns('age', df=4), poly('year', 2), 'education',
|
|
19
|
+
('age', 'education')])
|
|
20
|
+
X = spec.fit_transform(Wage)
|
|
21
|
+
|
|
22
|
+
pipe = make_pipeline(spec, LinearRegression())
|
|
23
|
+
grid = GridSearchCV(pipe, {'modelspec__terms__0__df': [2, 4, 8]})
|
|
24
|
+
grid.fit(Wage, Wage['wage'])
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`ModelSpec` was written for the labs of
|
|
28
|
+
[An Introduction to Statistical Learning with Python](https://www.statlearning.com),
|
|
29
|
+
and `from ISLP.models import ModelSpec` still works there.
|
|
30
|
+
|
|
31
|
+
Documentation: https://intro-stat-learning.github.io/modelmatrix
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
pip install modelmatrix
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Requires Python 3.11 or later. BSD licensed.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
jupytext:
|
|
3
|
+
formats: ipynb,md:myst
|
|
4
|
+
text_representation:
|
|
5
|
+
extension: .md
|
|
6
|
+
format_name: myst
|
|
7
|
+
format_version: 0.13
|
|
8
|
+
jupytext_version: 1.19.6
|
|
9
|
+
kernelspec:
|
|
10
|
+
display_name: python3
|
|
11
|
+
language: python
|
|
12
|
+
name: python3
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Derived features: using PCA on a subset of columns
|
|
16
|
+
|
|
17
|
+
The modelling tools in `modelmatrix` allow for
|
|
18
|
+
construction of transformers applied to features.
|
|
19
|
+
|
|
20
|
+
```{code-cell} ipython3
|
|
21
|
+
import numpy as np
|
|
22
|
+
from sklearn.decomposition import PCA
|
|
23
|
+
|
|
24
|
+
from ISLP import load_data
|
|
25
|
+
from modelmatrix import (ModelSpec,
|
|
26
|
+
pca,
|
|
27
|
+
Feature,
|
|
28
|
+
derived_feature,
|
|
29
|
+
build_columns)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```{code-cell} ipython3
|
|
33
|
+
Carseats = load_data('Carseats')
|
|
34
|
+
Carseats.columns
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Let's create a `ModelSpec` that is aware of all of the relevant columns.
|
|
38
|
+
|
|
39
|
+
```{code-cell} ipython3
|
|
40
|
+
design = ModelSpec(Carseats.columns.drop(['Sales']), intercept=True).fit(Carseats)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Suppose we want to make a `Feature` representing the first 3 principal components of the
|
|
44
|
+
features `['CompPrice', 'Income', 'Advertising', 'Population', 'Price']`.
|
|
45
|
+
|
|
46
|
+
+++
|
|
47
|
+
|
|
48
|
+
We first make a `Feature` that represents these five features columns, then `pca`
|
|
49
|
+
can be used to compute a new `Feature` that returns the first three principal components.
|
|
50
|
+
|
|
51
|
+
```{code-cell} ipython3
|
|
52
|
+
grouped = Feature(('CompPrice', 'Income', 'Advertising', 'Population', 'Price'), name='grouped', encoder=None)
|
|
53
|
+
sklearn_pca = PCA(n_components=3, whiten=True)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
We can now fit `sklearn_pca` and create our new feature.
|
|
57
|
+
|
|
58
|
+
```{code-cell} ipython3
|
|
59
|
+
grouped_features = build_columns(design.column_info_,
|
|
60
|
+
Carseats,
|
|
61
|
+
grouped)[0]
|
|
62
|
+
sklearn_pca.fit(grouped_features)
|
|
63
|
+
pca_var = derived_feature(['CompPrice', 'Income', 'Advertising', 'Population', 'Price'],
|
|
64
|
+
name='pca(grouped)', encoder=sklearn_pca)
|
|
65
|
+
derived_features, _ = build_columns(design.column_info_,
|
|
66
|
+
Carseats,
|
|
67
|
+
pca_var,
|
|
68
|
+
encoders=design.encoders_)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Helper function
|
|
72
|
+
|
|
73
|
+
The function `pca` encompasses these steps into a single function for convenience.
|
|
74
|
+
|
|
75
|
+
```{code-cell} ipython3
|
|
76
|
+
group_pca = pca(['CompPrice', 'Income', 'Advertising', 'Population', 'Price'],
|
|
77
|
+
n_components=3,
|
|
78
|
+
whiten=True,
|
|
79
|
+
name='grouped')
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```{code-cell} ipython3
|
|
83
|
+
pca_design = ModelSpec([group_pca], intercept=False)
|
|
84
|
+
mm_features = pca_design.fit_transform(Carseats)
|
|
85
|
+
mm_features.columns
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Direct comparison
|
|
89
|
+
|
|
90
|
+
```{code-cell} ipython3
|
|
91
|
+
X = np.asarray(Carseats[['CompPrice', 'Income', 'Advertising', 'Population', 'Price']])
|
|
92
|
+
sklearn_features = sklearn_pca.fit_transform(X)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```{code-cell} ipython3
|
|
96
|
+
np.linalg.norm(mm_features - sklearn_features), np.linalg.norm(mm_features - np.asarray(derived_features))
|
|
97
|
+
```
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
jupytext:
|
|
3
|
+
formats: ipynb,md:myst
|
|
4
|
+
text_representation:
|
|
5
|
+
extension: .md
|
|
6
|
+
format_name: myst
|
|
7
|
+
format_version: 0.13
|
|
8
|
+
jupytext_version: 1.19.6
|
|
9
|
+
kernelspec:
|
|
10
|
+
display_name: python3
|
|
11
|
+
language: python
|
|
12
|
+
name: python3
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# ANOVA using `ModelSpec`
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
We illustrate how to run specific ANOVA analyses
|
|
19
|
+
using `ModelSpec`, with statsmodels' `anova_lm`.
|
|
20
|
+
|
|
21
|
+
```{code-cell} ipython3
|
|
22
|
+
import numpy as np
|
|
23
|
+
import pandas as pd
|
|
24
|
+
|
|
25
|
+
from statsmodels.api import OLS
|
|
26
|
+
from statsmodels.stats.anova import anova_lm
|
|
27
|
+
|
|
28
|
+
from ISLP import load_data
|
|
29
|
+
from modelmatrix import ModelSpec, derived_feature
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
We will carry out two simple ANOVA analyses of the `Hitters` data.
|
|
33
|
+
We wish to predict a baseball player’s `Salary` on the
|
|
34
|
+
basis of various statistics associated with performance in the
|
|
35
|
+
previous year.
|
|
36
|
+
|
|
37
|
+
```{code-cell} ipython3
|
|
38
|
+
Hitters = load_data('Hitters')
|
|
39
|
+
np.isnan(Hitters['Salary']).sum()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
We see that `Salary` is missing for 59 players. The
|
|
44
|
+
`dropna()` method of data frames removes all of the rows that have missing
|
|
45
|
+
values in any variable (by default --- see `Hitters.dropna?`).
|
|
46
|
+
|
|
47
|
+
```{code-cell} ipython3
|
|
48
|
+
Hitters = Hitters.dropna()
|
|
49
|
+
Hitters.columns
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Grouping variables
|
|
53
|
+
|
|
54
|
+
A look at the [description](https://islp.readthedocs.io/en/latest/datasets/Hitters.html) of the data shows
|
|
55
|
+
that there are both career and 1986 offensive stats, as well as some defensive stats.
|
|
56
|
+
|
|
57
|
+
Let's group the offensive into recent and career offensive stats, as well as a group of defensive variables.
|
|
58
|
+
|
|
59
|
+
```{code-cell} ipython3
|
|
60
|
+
confounders = derived_feature(['Division', 'League', 'NewLeague'],
|
|
61
|
+
name='confounders')
|
|
62
|
+
offense_career = derived_feature(['CAtBat', 'CHits', 'CHmRun', 'CRuns', 'CRBI', 'CWalks'],
|
|
63
|
+
name='offense_career')
|
|
64
|
+
offense_1986 = derived_feature(['AtBat', 'Hits', 'HmRun', 'Runs', 'RBI', 'Walks'],
|
|
65
|
+
name='offense_1986')
|
|
66
|
+
defense_1986 = derived_feature(['PutOuts', 'Assists', 'Errors'],
|
|
67
|
+
name='defense_1986')
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
We'll first do a sequential ANOVA where terms are added sequentially
|
|
71
|
+
|
|
72
|
+
```{code-cell} ipython3
|
|
73
|
+
design = ModelSpec([confounders, offense_career, defense_1986, offense_1986], intercept=True).fit(Hitters)
|
|
74
|
+
Y = np.array(Hitters['Salary'])
|
|
75
|
+
X = design.transform(Hitters)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```{code-cell} ipython3
|
|
79
|
+
M = OLS(Y, X).fit()
|
|
80
|
+
M.summary().tables[1]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
We'll first produce the sequential, or Type I ANOVA results. This builds up a model sequentially and compares
|
|
84
|
+
two successive models.
|
|
85
|
+
|
|
86
|
+
```{code-cell} ipython3
|
|
87
|
+
df = anova_lm(*[OLS(Y, D).fit() for D in design.build_sequence(Hitters, anova_type='sequential')])
|
|
88
|
+
df.index = design.names
|
|
89
|
+
df
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
We can similarly compute the Type II ANOVA results which drops each term and compares to the full model.
|
|
93
|
+
|
|
94
|
+
```{code-cell} ipython3
|
|
95
|
+
D_full = design.transform(Hitters)
|
|
96
|
+
OLS_full = OLS(Y, D_full).fit()
|
|
97
|
+
dfs = []
|
|
98
|
+
for d in design.build_sequence(Hitters, anova_type='drop'):
|
|
99
|
+
dfs.append(anova_lm(OLS(Y,d).fit(), OLS_full).iloc[1:])
|
|
100
|
+
df = pd.concat(dfs)
|
|
101
|
+
df.index = design.names
|
|
102
|
+
df
|
|
103
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Sphinx configuration for the modelmatrix API reference.
|
|
2
|
+
#
|
|
3
|
+
# The narrative docs are a Jupyter Book 2 (MyST) site, which has no autodoc;
|
|
4
|
+
# this small Sphinx project builds the API reference from docstrings into
|
|
5
|
+
# docs/_build/html/api, next to the book. See .github/workflows/build_docs.yml.
|
|
6
|
+
#
|
|
7
|
+
# Build: sphinx-build -b html docs/api docs/_build/html/api
|
|
8
|
+
|
|
9
|
+
project = 'modelmatrix API Reference'
|
|
10
|
+
author = 'Jonathan Taylor'
|
|
11
|
+
|
|
12
|
+
extensions = [
|
|
13
|
+
'sphinx.ext.autodoc',
|
|
14
|
+
'sphinx.ext.napoleon',
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
autodoc_default_options = {
|
|
18
|
+
'members': True,
|
|
19
|
+
'show-inheritance': True,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
html_theme = 'sphinx_book_theme'
|
|
23
|
+
html_title = 'modelmatrix API Reference'
|
|
24
|
+
html_theme_options = {
|
|
25
|
+
'repository_url': 'https://github.com/intro-stat-learning/modelmatrix',
|
|
26
|
+
'use_repository_button': True,
|
|
27
|
+
'home_page_in_toc': True,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _skip_sklearn_metadata_routing(app, what, name, obj, skip, options):
|
|
32
|
+
# scikit-learn's metadata-routing plumbing (set_{fit,transform,...}_request,
|
|
33
|
+
# added to every estimator subclass, and get_metadata_routing) is not part of
|
|
34
|
+
# the modelmatrix API
|
|
35
|
+
if (name.startswith('set_') and name.endswith('_request')) or name == 'get_metadata_routing':
|
|
36
|
+
return True
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def setup(app):
|
|
41
|
+
app.connect('autodoc-skip-member', _skip_sklearn_metadata_routing)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Terms
|
|
2
|
+
=====
|
|
3
|
+
|
|
4
|
+
Helpers that make terms
|
|
5
|
+
-----------------------
|
|
6
|
+
|
|
7
|
+
.. autofunction:: modelmatrix.poly
|
|
8
|
+
.. autofunction:: modelmatrix.ns
|
|
9
|
+
.. autofunction:: modelmatrix.bs
|
|
10
|
+
.. autofunction:: modelmatrix.pca
|
|
11
|
+
.. autofunction:: modelmatrix.contrast
|
|
12
|
+
.. autofunction:: modelmatrix.ordinal
|
|
13
|
+
.. autofunction:: modelmatrix.derived_feature
|
|
14
|
+
.. autofunction:: modelmatrix.build_columns
|
|
15
|
+
|
|
16
|
+
Terms and columns
|
|
17
|
+
-----------------
|
|
18
|
+
|
|
19
|
+
.. autoclass:: modelmatrix.Feature
|
|
20
|
+
.. autoclass:: modelmatrix.Column
|
|
21
|
+
:members: get_columns
|
|
22
|
+
|
|
23
|
+
Encoders of categoricals
|
|
24
|
+
------------------------
|
|
25
|
+
|
|
26
|
+
.. autoclass:: modelmatrix.Contrast
|
|
27
|
+
:members: fit, transform
|
|
28
|
+
.. autoclass:: modelmatrix.Ordinal
|
|
29
|
+
:members: fit, transform
|