anchorboosting 0.0.1__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.
- anchorboosting-0.0.1/.github/workflows/build.yaml +75 -0
- anchorboosting-0.0.1/.github/workflows/ci.yml +56 -0
- anchorboosting-0.0.1/.gitignore +4 -0
- anchorboosting-0.0.1/.pre-commit-config.yaml +29 -0
- anchorboosting-0.0.1/CHANGELOG.rst +7 -0
- anchorboosting-0.0.1/LICENSE +13 -0
- anchorboosting-0.0.1/PKG-INFO +224 -0
- anchorboosting-0.0.1/README.md +209 -0
- anchorboosting-0.0.1/anchorboosting/__init__.py +4 -0
- anchorboosting-0.0.1/anchorboosting/models.py +368 -0
- anchorboosting-0.0.1/anchorboosting/objectives/__init__.py +11 -0
- anchorboosting-0.0.1/anchorboosting/objectives/anchor_objectives.py +123 -0
- anchorboosting-0.0.1/anchorboosting/objectives/mixins.py +237 -0
- anchorboosting-0.0.1/anchorboosting/simulate.py +25 -0
- anchorboosting-0.0.1/anchorboosting/utils.py +84 -0
- anchorboosting-0.0.1/anchorboosting.egg-info/PKG-INFO +224 -0
- anchorboosting-0.0.1/anchorboosting.egg-info/SOURCES.txt +33 -0
- anchorboosting-0.0.1/anchorboosting.egg-info/dependency_links.txt +1 -0
- anchorboosting-0.0.1/anchorboosting.egg-info/requires.txt +3 -0
- anchorboosting-0.0.1/anchorboosting.egg-info/top_level.txt +1 -0
- anchorboosting-0.0.1/docs/changelog.rst +1 -0
- anchorboosting-0.0.1/docs/index.rst +31 -0
- anchorboosting-0.0.1/environment.yml +22 -0
- anchorboosting-0.0.1/pyproject.toml +28 -0
- anchorboosting-0.0.1/readthedocs.yaml +17 -0
- anchorboosting-0.0.1/setup.cfg +4 -0
- anchorboosting-0.0.1/tests/test_anchor_boosting.py +180 -0
- anchorboosting-0.0.1/tests/test_anchor_objectives.py +102 -0
- anchorboosting-0.0.1/tests/test_classification_mixins.py +92 -0
- anchorboosting-0.0.1/tests/test_compare_to_lgbm.py +237 -0
- anchorboosting-0.0.1/tests/test_derivatives.py +143 -0
- anchorboosting-0.0.1/tests/test_refit.py +35 -0
- anchorboosting-0.0.1/tests/test_regression_mixin.py +25 -0
- anchorboosting-0.0.1/tests/test_update.py +35 -0
- anchorboosting-0.0.1/tests/test_utils.py +74 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
on:
|
|
2
|
+
pull_request:
|
|
3
|
+
release:
|
|
4
|
+
types:
|
|
5
|
+
- published
|
|
6
|
+
|
|
7
|
+
name: release
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
|
|
11
|
+
python-build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v3
|
|
16
|
+
|
|
17
|
+
- uses: actions/setup-python@v4
|
|
18
|
+
name: Install Python
|
|
19
|
+
with:
|
|
20
|
+
python-version: '3.10'
|
|
21
|
+
|
|
22
|
+
- name: Install build dependencies
|
|
23
|
+
run: python -m pip install build
|
|
24
|
+
|
|
25
|
+
- name: Build source distribution and wheel
|
|
26
|
+
run: python -m build --sdist --wheel
|
|
27
|
+
|
|
28
|
+
- name: Install wheel
|
|
29
|
+
run: python -m pip install dist/*.whl
|
|
30
|
+
|
|
31
|
+
- name: Test import
|
|
32
|
+
run: cd .. && python -c "from anchorboosting import AnchorBooster"
|
|
33
|
+
|
|
34
|
+
- uses: actions/upload-artifact@v4
|
|
35
|
+
with:
|
|
36
|
+
name: wheels
|
|
37
|
+
path: dist/*
|
|
38
|
+
|
|
39
|
+
upload-testpypi:
|
|
40
|
+
needs: [python-build]
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
if: github.event_name == 'release' && github.event.action == 'published'
|
|
43
|
+
environment:
|
|
44
|
+
name: test_release
|
|
45
|
+
url: https://test.pypi.org/p/anchorboosting
|
|
46
|
+
permissions:
|
|
47
|
+
id-token: write
|
|
48
|
+
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/download-artifact@v4
|
|
51
|
+
with:
|
|
52
|
+
name: wheels
|
|
53
|
+
path: dist
|
|
54
|
+
|
|
55
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
56
|
+
with:
|
|
57
|
+
repository-url: https://test.pypi.org/legacy/
|
|
58
|
+
|
|
59
|
+
upload-pypi:
|
|
60
|
+
needs: [python-build, upload-testpypi]
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
if: github.event_name == 'release' && github.event.action == 'published'
|
|
63
|
+
environment:
|
|
64
|
+
name: release
|
|
65
|
+
url: https://pypi.org/p/anchorboosting
|
|
66
|
+
permissions:
|
|
67
|
+
id-token: write
|
|
68
|
+
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/download-artifact@v4
|
|
71
|
+
with:
|
|
72
|
+
name: wheels
|
|
73
|
+
path: dist
|
|
74
|
+
|
|
75
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [ main ]
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
name: CI
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
|
|
11
|
+
test:
|
|
12
|
+
name: Unit tests
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
defaults:
|
|
17
|
+
run:
|
|
18
|
+
# see https://github.com/conda-incubator/setup-miniconda/#important
|
|
19
|
+
shell: bash -l {0}
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v3
|
|
22
|
+
- name: Set up micromamba
|
|
23
|
+
uses: mamba-org/setup-micromamba@d05808540d968a55ca33c798e0661fb98f533c73
|
|
24
|
+
with:
|
|
25
|
+
micromamba-version: 1.5.10-0
|
|
26
|
+
environment-file: environment.yml
|
|
27
|
+
- name: Install repository
|
|
28
|
+
run: python -m pip install --no-build-isolation --no-deps --disable-pip-version-check -e .
|
|
29
|
+
- name: Pytest
|
|
30
|
+
run: pytest --cov --cov-report xml tests
|
|
31
|
+
- name: codecov
|
|
32
|
+
uses: codecov/codecov-action@v4.3.1
|
|
33
|
+
with:
|
|
34
|
+
file: ./coverage.xml
|
|
35
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
36
|
+
name: pytest-python${{ matrix.PYTHON_VERSION }}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
pre-commit-checks:
|
|
40
|
+
name: "Pre-commit checks - Python 3.12"
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
|
|
45
|
+
- name: Checkout branch
|
|
46
|
+
uses: actions/checkout@v3
|
|
47
|
+
with:
|
|
48
|
+
ref: ${{ github.head_ref }}
|
|
49
|
+
|
|
50
|
+
- name: Install Python 3.12
|
|
51
|
+
uses: actions/setup-python@v2
|
|
52
|
+
with:
|
|
53
|
+
python-version: 3.12
|
|
54
|
+
|
|
55
|
+
- name: Run pre-commit checks
|
|
56
|
+
uses: pre-commit/action@v3.0.1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/Quantco/pre-commit-mirrors-black
|
|
3
|
+
rev: 22.6.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: black-conda
|
|
6
|
+
args:
|
|
7
|
+
- --safe
|
|
8
|
+
- --target-version=py38
|
|
9
|
+
- repo: https://github.com/Quantco/pre-commit-mirrors-isort
|
|
10
|
+
rev: '5.10.1'
|
|
11
|
+
hooks:
|
|
12
|
+
- id: isort-conda
|
|
13
|
+
additional_dependencies: [toml]
|
|
14
|
+
- repo: https://github.com/Quantco/pre-commit-mirrors-flake8
|
|
15
|
+
rev: 5.0.4
|
|
16
|
+
hooks:
|
|
17
|
+
- id: flake8-conda
|
|
18
|
+
args:
|
|
19
|
+
- --max-line-length=88
|
|
20
|
+
- --extend-ignore=E203
|
|
21
|
+
- repo: https://github.com/Quantco/pre-commit-mirrors-mypy
|
|
22
|
+
rev: "0.971"
|
|
23
|
+
hooks:
|
|
24
|
+
- id: mypy-conda
|
|
25
|
+
additional_dependencies: [-c, conda-forge, types-setuptools]
|
|
26
|
+
- repo: https://github.com/Quantco/pre-commit-mirrors-pyupgrade
|
|
27
|
+
rev: 2.37.3
|
|
28
|
+
hooks:
|
|
29
|
+
- id: pyupgrade-conda
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
BSD 3-clause license
|
|
2
|
+
Copyright (c) 2022 Malte Londschien
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
8
|
+
|
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
10
|
+
|
|
11
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
12
|
+
|
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: anchorboosting
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Anchor Boosting
|
|
5
|
+
Author-email: Malte Londschien <malte@londschien.ch>
|
|
6
|
+
Project-URL: homepage, https://github.com/mlondschien/anchorboosting/
|
|
7
|
+
Classifier: Programming Language :: Python
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: numpy
|
|
12
|
+
Requires-Dist: scipy
|
|
13
|
+
Requires-Dist: lightgbm
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# Anchor Boosting
|
|
17
|
+
|
|
18
|
+
This repository combines ideas from [1, 2 and 3].
|
|
19
|
+
[1] suggests regularizing linear regression with the correlation between a so-called anchor variable and the regression's residuals.
|
|
20
|
+
The anchor variable is assumed to be exogenous to the system, i.e., not causally affected by covariates, the outcome, or relevant hidden variables.
|
|
21
|
+
[1] show that such regularization induces robustness of the linear regression model to shift interventions with limited magnitude in directions as observed in the data.
|
|
22
|
+
|
|
23
|
+
[2] proposes to generalize this to nonlinear regression by simply optimizing, e.g., via boosting, the regularized anchor regression loss, replacing linear regression with a more flexible model class.
|
|
24
|
+
|
|
25
|
+
Lastly, [3] give ideas to generalize anchor regression to classification.
|
|
26
|
+
|
|
27
|
+
This repository combines these approaches and implements non-linear anchor (multiclass-) classification using LGBM.
|
|
28
|
+
|
|
29
|
+
## Classification via boosting
|
|
30
|
+
|
|
31
|
+
We first describe how to explicitly solve a classification problem with boosting.
|
|
32
|
+
This includes calculating the gradient and the diagonal of the hessian of the loss with respect to model parameters.
|
|
33
|
+
In each boosting step, the gradient is fit with a weak learner (CART tree).
|
|
34
|
+
The diagonal of the hessian is used as a stopping criterium only (`min_hessian_in_leaf`).
|
|
35
|
+
|
|
36
|
+
We separately describe two-class and multi-class classification, even though the former is a special case of the latter.
|
|
37
|
+
$K$-class classification involves learning $K$ scores (parameters), each fitted with a single weak learner.
|
|
38
|
+
I.e., the boosting algorithm will train $K$ trees in each set.
|
|
39
|
+
|
|
40
|
+
### Two-class classification
|
|
41
|
+
|
|
42
|
+
Consider a setup with observations $x_i \in \mathbb{R}^p$ with outcomes $y_i \in \{-1, 1\}$ for $i=1, \ldots, n$.
|
|
43
|
+
We assign raw scores $f_i \in \mathbb{R}$ to each observation and use the expit to obtain probability predictions.
|
|
44
|
+
The estimated probability of observation $x_i$ with raw score $f_i$ to belong to class 1 is $p_i = \frac{e^f}{1 + e^f} = (1 + e^{-f})^{-1}$.
|
|
45
|
+
The log-likelihood of raw scores $`f=(f_i)_{i=1}^n`$ is
|
|
46
|
+
|
|
47
|
+
$$\ell(f, y) = -\sum_{i=1}^n \log(1 + e^{-yf}).$$
|
|
48
|
+
|
|
49
|
+
The gradient of the log-likelihood is
|
|
50
|
+
|
|
51
|
+
$$
|
|
52
|
+
\frac{d}{d f_i} \ell(f, y) = y \frac{e^{-yf}}{1 + e^{-yf}} =
|
|
53
|
+
\begin{cases}
|
|
54
|
+
1 - p & y = 1 \\
|
|
55
|
+
-p & y = 0
|
|
56
|
+
\end{cases}
|
|
57
|
+
$$
|
|
58
|
+
|
|
59
|
+
The (diagonal of the) Hessian of the log-likelihood is
|
|
60
|
+
|
|
61
|
+
$$
|
|
62
|
+
\frac{d^2}{d^2f_i} \ell(f, y) = (1 - p_i) p_i.
|
|
63
|
+
$$
|
|
64
|
+
|
|
65
|
+
### Multiclass classification
|
|
66
|
+
Consider a setup with observations $x_i \in \mathbb{R}^p$ with outcomes $y_i \in \{1, \ldots, K\}$ for $i=1, \ldots, n$.
|
|
67
|
+
We assign raw scores $f_i = (f_{i, 1}, \ldots, f_{i, K}) \in \mathbb{R}^K$ to each observation and use cross-entropy to obtain probability predictions.
|
|
68
|
+
For $k = 1, \ldots, K$ and $i=1, \ldots, n$ the estimated probability of observation $x_i$ with raw score $f_i$ to belong to class $k$ is $p_{i, k} := \exp(f_{i, k}) / \sum_{j=1}^K \exp(f_{i, j})$. The log-likelihood of raw scores $`(f_i)_{i=1}^n`$ is then
|
|
69
|
+
```math
|
|
70
|
+
\ell\left((f_{i, k})_{i=1, \ldots, n}^{k=1, \ldots, K}, (y_i)_{i=1}^n\right) = \sum_{i=1}^n \left(f_{i, y} - \log\left(\sum_{j=1}^K \exp(f_{i,j})\right)\right).
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The gradient of the log-likelihood is
|
|
74
|
+
|
|
75
|
+
$$
|
|
76
|
+
\frac{d}{df_{i, k}} \ell(f, y) = \begin{cases}
|
|
77
|
+
1 - p_{i, k} & y_i = k \\
|
|
78
|
+
-p_{i, k} & y_i \neq k \\
|
|
79
|
+
\end{cases}
|
|
80
|
+
$$
|
|
81
|
+
|
|
82
|
+
The (diagonal of the) Hessian of the log-likelihood is
|
|
83
|
+
```math
|
|
84
|
+
\frac{d^2}{d^2 f_{i, k}} \ell(f, y) = (1 - p_{i, k}) p_{i, k}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Anchorized classification
|
|
88
|
+
|
|
89
|
+
[1] suggest adding a regularization term based on an "anchor variable" $A$ to the linear least squares optimization problem to improve distributional robustness.
|
|
90
|
+
|
|
91
|
+
Say additional to features and outcomes we observe anchor values $a_i \in \mathbb{R}^q, i=1,\ldots K$.
|
|
92
|
+
Write $A = (a_i)_{i=1}^n \in \mathbb{R}^{n \times q}$ and $\pi_A$ for the linear projection onto the column space of $A$.
|
|
93
|
+
[1] show that
|
|
94
|
+
|
|
95
|
+
$$
|
|
96
|
+
b^\gamma = \underset{b}{\arg\min} \|(\mathrm{Id} - \pi_A)(Y - Xb)\|_2^2 + \gamma\|\pi_A(Y - Xb)\|_2^2
|
|
97
|
+
$$
|
|
98
|
+
|
|
99
|
+
minimizes the linear model's worst-case risk with respect to certain shift interventions as seen in the data.
|
|
100
|
+
|
|
101
|
+
[2] suggests applying anchor regression to nonlinear regression by boosting the above anchor loss with a flexible (nonlinear) learner.
|
|
102
|
+
[3] presents an idea to generalize anchor regression to different distributions than the Gaussian distribution, i.e., using different losses than the squared error.
|
|
103
|
+
One interesting case is the logistic loss for (two-class) classification.
|
|
104
|
+
This is mostly based on intelligently defining residuals to be used in the equivalent classification anchor loss.
|
|
105
|
+
|
|
106
|
+
[4] proposes the usage of a different type of residuals for classification outside of the use with anchor regression.
|
|
107
|
+
We apply their residuals in the context of anchor classification.
|
|
108
|
+
|
|
109
|
+
### Anchorized two-class classification according to [3]
|
|
110
|
+
|
|
111
|
+
Note that again $y \in \{-1, 1\}$.
|
|
112
|
+
[3] suggest defining residuals as
|
|
113
|
+
|
|
114
|
+
$$r_i = \frac{d}{d f}(\ell(f, y)) = y \frac{e^{-yf}}{1 + e^{-yf}} =
|
|
115
|
+
\begin{cases}
|
|
116
|
+
1 - p & y = 1 \\
|
|
117
|
+
-p & y = 0
|
|
118
|
+
\end{cases}
|
|
119
|
+
$$
|
|
120
|
+
|
|
121
|
+
For some tuning parameter $\gamma$, we add the regularization term $(\gamma - 1) \| \pi_A r \|_2^2$ to our optimization problem.
|
|
122
|
+
|
|
123
|
+
$$
|
|
124
|
+
\hat f = \underset{f}{\arg \min} \ \ell(f, Y) + (\gamma - 1) \|\pi_A r\|_2^2
|
|
125
|
+
$$
|
|
126
|
+
|
|
127
|
+
This encourages uncorrelatedness between the residuals and the anchor and, hopefully, better domain generalization. To optimize this, we also calculate the gradient of the regularization term. First, note that
|
|
128
|
+
|
|
129
|
+
$$
|
|
130
|
+
\frac{d}{d f_i} p_i = p_i (1 - p_i)
|
|
131
|
+
$$
|
|
132
|
+
|
|
133
|
+
such that
|
|
134
|
+
|
|
135
|
+
$$
|
|
136
|
+
\frac{d}{d f_i} \| \pi_A r \|_2^2 = 2 \pi_A r \cdot p (1 - p)
|
|
137
|
+
$$
|
|
138
|
+
|
|
139
|
+
### Anchorized multiclass classification according to [3]
|
|
140
|
+
|
|
141
|
+
We combine the notions of [1, 2, 3].
|
|
142
|
+
Motivated by [3], define residuals
|
|
143
|
+
```math
|
|
144
|
+
r_{i, k} =
|
|
145
|
+
\frac{d}{df_{i, k}} \ell(f, y) =
|
|
146
|
+
\begin{cases}
|
|
147
|
+
1 - p_{i, k} & y_i = k \\
|
|
148
|
+
-p_{i, k} & y_i \neq k
|
|
149
|
+
\end{cases}
|
|
150
|
+
```
|
|
151
|
+
such that for all $i$ we have $\sum_{k} r_{i, k} = 0$.
|
|
152
|
+
|
|
153
|
+
For some tuning parameter $\gamma$, we add the regularization term $(\gamma - 1) \| \pi_A r \|_2^2$ to our optimization problem.
|
|
154
|
+
|
|
155
|
+
$$
|
|
156
|
+
\hat f = \underset{f}{\arg \min} \ \ell(f, Y) + (\gamma - 1) \|\pi_A r\|_2^2
|
|
157
|
+
$$
|
|
158
|
+
|
|
159
|
+
This encourages uncorrelatedness between the residuals and the anchor and, hopefully, better domain generalization. To optimize this, we also calculate the gradient of the regularization term. First, note that
|
|
160
|
+
|
|
161
|
+
$$
|
|
162
|
+
\frac{d}{d f_{i, k}} p_{i, j} =
|
|
163
|
+
\frac{d}{d f_{i, k}} \frac{\exp(f_{i, j})}{\sum_l \exp(f_{i, l})} =
|
|
164
|
+
\begin{cases}
|
|
165
|
+
\frac{\exp(f_{i, k})}{\sum_l \exp(f_{i, l})} - \frac{\exp(f_{i, k})^2}{(\sum_l \exp(f_{i, l}))^2} & j = k \\
|
|
166
|
+
-\frac{\exp(f_{i, k})\exp{(f_{i, j})}}{(\sum_l \exp(f_{i, l}))^2} & j \neq k
|
|
167
|
+
\end{cases} =
|
|
168
|
+
\begin{cases}
|
|
169
|
+
p_{i, j} - p_{i, j}p_{i, k} & j = k \\
|
|
170
|
+
-p_{i, j} p_{i, k} & j \neq k
|
|
171
|
+
\end{cases}.
|
|
172
|
+
$$
|
|
173
|
+
|
|
174
|
+
Then,
|
|
175
|
+
|
|
176
|
+
```math
|
|
177
|
+
\frac{d}{d f_{i, k}} \| \pi_A r\|_2^2 = 2 \pi_A r \cdot \left(\begin{cases}
|
|
178
|
+
p_{i, j} - p_{i, j}p_{i, k} & l=i, j = k \\
|
|
179
|
+
-p_{i, j} p_{i, k} & l=i, j \neq k \\
|
|
180
|
+
0 & l \neq i
|
|
181
|
+
\end{cases}\right)_{l=1, \ldots, n}^{j=1, \ldots K}
|
|
182
|
+
=(\pi_A r)_{i, k} \ p_{i, k} - \sum_{l=1}^K (\pi_A r)_{i, l} \ p_{i, l}.
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
<!---
|
|
186
|
+
The diagonal of the hessian is equal to
|
|
187
|
+
|
|
188
|
+
$$
|
|
189
|
+
\frac{d^2}{d f_{i, k}^2} \| \pi_A r\|^2 = 2 \pi_A r \cdot
|
|
190
|
+
\left(\begin{cases}
|
|
191
|
+
p_{i, j} - 3 p_{i, j}^2 + 2 p_{i, j}^3 & l=i, j = k \\
|
|
192
|
+
2 p_{i, j} p_{i, k}^2 - p_{i, j} p{i, k} & l=i, j \neq k \\
|
|
193
|
+
0 & l \neq i
|
|
194
|
+
\end{cases}\right)_{l=1, \ldots, n}^{j=1, \ldots K} +
|
|
195
|
+
2 \pi_A \left(\begin{cases}
|
|
196
|
+
p_{i, j} - p_{i, j}p_{i, k} & l=i, j = k \\
|
|
197
|
+
- p_{i, j} p_{i, k} & l=i, j \neq k \\
|
|
198
|
+
0 & l \neq i
|
|
199
|
+
\end{cases}\right)_{l=1, \ldots, n}^{j=1, \ldots K} \cdot \left(\begin{cases}
|
|
200
|
+
p_{i, j} - p_{i, j}p_{i, k} & l=i, j = k \\
|
|
201
|
+
- p_{i, j} p_{i, k} & l=i, j \neq k \\
|
|
202
|
+
0 & l \neq i
|
|
203
|
+
\end{cases}\right)_{l=1, \ldots, n}^{j=1, \ldots K}
|
|
204
|
+
$$
|
|
205
|
+
|
|
206
|
+
$$
|
|
207
|
+
\frac{d^2}{d f_{i, k} d f_{i, l}} p_{i, j} =
|
|
208
|
+
\begin{cases}
|
|
209
|
+
(1 - 2 p_{i, j}) p_{i, j} (1 - p_{i, j}) & j = k \\
|
|
210
|
+
p_{i, j}^2 p_{i, k} & j \neq k
|
|
211
|
+
\end{cases}
|
|
212
|
+
$$ -->
|
|
213
|
+
|
|
214
|
+
## Anchorized two-class classification with residuals motivated by [4]
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
## References
|
|
219
|
+
|
|
220
|
+
[1] Rothenhäusler, D., N. Meinshausen, P. Bühlmann, and J. Peters (2021). Anchor regression: Heterogeneous data meet causality. Journal of the Royal Statistical Society Series B (Statistical Methodology) 83(2), 215–246.
|
|
221
|
+
|
|
222
|
+
[2] Bühlmann, P. (2020). Invariance, causality and robustness. Statistical Science 35(3), 404– 426.
|
|
223
|
+
|
|
224
|
+
[3] Kook, L., B. Sick, and P. Bühlmann (2022). Distributional anchor regression. Statistics and Computing 32(3), 1–19.
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Anchor Boosting
|
|
2
|
+
|
|
3
|
+
This repository combines ideas from [1, 2 and 3].
|
|
4
|
+
[1] suggests regularizing linear regression with the correlation between a so-called anchor variable and the regression's residuals.
|
|
5
|
+
The anchor variable is assumed to be exogenous to the system, i.e., not causally affected by covariates, the outcome, or relevant hidden variables.
|
|
6
|
+
[1] show that such regularization induces robustness of the linear regression model to shift interventions with limited magnitude in directions as observed in the data.
|
|
7
|
+
|
|
8
|
+
[2] proposes to generalize this to nonlinear regression by simply optimizing, e.g., via boosting, the regularized anchor regression loss, replacing linear regression with a more flexible model class.
|
|
9
|
+
|
|
10
|
+
Lastly, [3] give ideas to generalize anchor regression to classification.
|
|
11
|
+
|
|
12
|
+
This repository combines these approaches and implements non-linear anchor (multiclass-) classification using LGBM.
|
|
13
|
+
|
|
14
|
+
## Classification via boosting
|
|
15
|
+
|
|
16
|
+
We first describe how to explicitly solve a classification problem with boosting.
|
|
17
|
+
This includes calculating the gradient and the diagonal of the hessian of the loss with respect to model parameters.
|
|
18
|
+
In each boosting step, the gradient is fit with a weak learner (CART tree).
|
|
19
|
+
The diagonal of the hessian is used as a stopping criterium only (`min_hessian_in_leaf`).
|
|
20
|
+
|
|
21
|
+
We separately describe two-class and multi-class classification, even though the former is a special case of the latter.
|
|
22
|
+
$K$-class classification involves learning $K$ scores (parameters), each fitted with a single weak learner.
|
|
23
|
+
I.e., the boosting algorithm will train $K$ trees in each set.
|
|
24
|
+
|
|
25
|
+
### Two-class classification
|
|
26
|
+
|
|
27
|
+
Consider a setup with observations $x_i \in \mathbb{R}^p$ with outcomes $y_i \in \{-1, 1\}$ for $i=1, \ldots, n$.
|
|
28
|
+
We assign raw scores $f_i \in \mathbb{R}$ to each observation and use the expit to obtain probability predictions.
|
|
29
|
+
The estimated probability of observation $x_i$ with raw score $f_i$ to belong to class 1 is $p_i = \frac{e^f}{1 + e^f} = (1 + e^{-f})^{-1}$.
|
|
30
|
+
The log-likelihood of raw scores $`f=(f_i)_{i=1}^n`$ is
|
|
31
|
+
|
|
32
|
+
$$\ell(f, y) = -\sum_{i=1}^n \log(1 + e^{-yf}).$$
|
|
33
|
+
|
|
34
|
+
The gradient of the log-likelihood is
|
|
35
|
+
|
|
36
|
+
$$
|
|
37
|
+
\frac{d}{d f_i} \ell(f, y) = y \frac{e^{-yf}}{1 + e^{-yf}} =
|
|
38
|
+
\begin{cases}
|
|
39
|
+
1 - p & y = 1 \\
|
|
40
|
+
-p & y = 0
|
|
41
|
+
\end{cases}
|
|
42
|
+
$$
|
|
43
|
+
|
|
44
|
+
The (diagonal of the) Hessian of the log-likelihood is
|
|
45
|
+
|
|
46
|
+
$$
|
|
47
|
+
\frac{d^2}{d^2f_i} \ell(f, y) = (1 - p_i) p_i.
|
|
48
|
+
$$
|
|
49
|
+
|
|
50
|
+
### Multiclass classification
|
|
51
|
+
Consider a setup with observations $x_i \in \mathbb{R}^p$ with outcomes $y_i \in \{1, \ldots, K\}$ for $i=1, \ldots, n$.
|
|
52
|
+
We assign raw scores $f_i = (f_{i, 1}, \ldots, f_{i, K}) \in \mathbb{R}^K$ to each observation and use cross-entropy to obtain probability predictions.
|
|
53
|
+
For $k = 1, \ldots, K$ and $i=1, \ldots, n$ the estimated probability of observation $x_i$ with raw score $f_i$ to belong to class $k$ is $p_{i, k} := \exp(f_{i, k}) / \sum_{j=1}^K \exp(f_{i, j})$. The log-likelihood of raw scores $`(f_i)_{i=1}^n`$ is then
|
|
54
|
+
```math
|
|
55
|
+
\ell\left((f_{i, k})_{i=1, \ldots, n}^{k=1, \ldots, K}, (y_i)_{i=1}^n\right) = \sum_{i=1}^n \left(f_{i, y} - \log\left(\sum_{j=1}^K \exp(f_{i,j})\right)\right).
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The gradient of the log-likelihood is
|
|
59
|
+
|
|
60
|
+
$$
|
|
61
|
+
\frac{d}{df_{i, k}} \ell(f, y) = \begin{cases}
|
|
62
|
+
1 - p_{i, k} & y_i = k \\
|
|
63
|
+
-p_{i, k} & y_i \neq k \\
|
|
64
|
+
\end{cases}
|
|
65
|
+
$$
|
|
66
|
+
|
|
67
|
+
The (diagonal of the) Hessian of the log-likelihood is
|
|
68
|
+
```math
|
|
69
|
+
\frac{d^2}{d^2 f_{i, k}} \ell(f, y) = (1 - p_{i, k}) p_{i, k}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Anchorized classification
|
|
73
|
+
|
|
74
|
+
[1] suggest adding a regularization term based on an "anchor variable" $A$ to the linear least squares optimization problem to improve distributional robustness.
|
|
75
|
+
|
|
76
|
+
Say additional to features and outcomes we observe anchor values $a_i \in \mathbb{R}^q, i=1,\ldots K$.
|
|
77
|
+
Write $A = (a_i)_{i=1}^n \in \mathbb{R}^{n \times q}$ and $\pi_A$ for the linear projection onto the column space of $A$.
|
|
78
|
+
[1] show that
|
|
79
|
+
|
|
80
|
+
$$
|
|
81
|
+
b^\gamma = \underset{b}{\arg\min} \|(\mathrm{Id} - \pi_A)(Y - Xb)\|_2^2 + \gamma\|\pi_A(Y - Xb)\|_2^2
|
|
82
|
+
$$
|
|
83
|
+
|
|
84
|
+
minimizes the linear model's worst-case risk with respect to certain shift interventions as seen in the data.
|
|
85
|
+
|
|
86
|
+
[2] suggests applying anchor regression to nonlinear regression by boosting the above anchor loss with a flexible (nonlinear) learner.
|
|
87
|
+
[3] presents an idea to generalize anchor regression to different distributions than the Gaussian distribution, i.e., using different losses than the squared error.
|
|
88
|
+
One interesting case is the logistic loss for (two-class) classification.
|
|
89
|
+
This is mostly based on intelligently defining residuals to be used in the equivalent classification anchor loss.
|
|
90
|
+
|
|
91
|
+
[4] proposes the usage of a different type of residuals for classification outside of the use with anchor regression.
|
|
92
|
+
We apply their residuals in the context of anchor classification.
|
|
93
|
+
|
|
94
|
+
### Anchorized two-class classification according to [3]
|
|
95
|
+
|
|
96
|
+
Note that again $y \in \{-1, 1\}$.
|
|
97
|
+
[3] suggest defining residuals as
|
|
98
|
+
|
|
99
|
+
$$r_i = \frac{d}{d f}(\ell(f, y)) = y \frac{e^{-yf}}{1 + e^{-yf}} =
|
|
100
|
+
\begin{cases}
|
|
101
|
+
1 - p & y = 1 \\
|
|
102
|
+
-p & y = 0
|
|
103
|
+
\end{cases}
|
|
104
|
+
$$
|
|
105
|
+
|
|
106
|
+
For some tuning parameter $\gamma$, we add the regularization term $(\gamma - 1) \| \pi_A r \|_2^2$ to our optimization problem.
|
|
107
|
+
|
|
108
|
+
$$
|
|
109
|
+
\hat f = \underset{f}{\arg \min} \ \ell(f, Y) + (\gamma - 1) \|\pi_A r\|_2^2
|
|
110
|
+
$$
|
|
111
|
+
|
|
112
|
+
This encourages uncorrelatedness between the residuals and the anchor and, hopefully, better domain generalization. To optimize this, we also calculate the gradient of the regularization term. First, note that
|
|
113
|
+
|
|
114
|
+
$$
|
|
115
|
+
\frac{d}{d f_i} p_i = p_i (1 - p_i)
|
|
116
|
+
$$
|
|
117
|
+
|
|
118
|
+
such that
|
|
119
|
+
|
|
120
|
+
$$
|
|
121
|
+
\frac{d}{d f_i} \| \pi_A r \|_2^2 = 2 \pi_A r \cdot p (1 - p)
|
|
122
|
+
$$
|
|
123
|
+
|
|
124
|
+
### Anchorized multiclass classification according to [3]
|
|
125
|
+
|
|
126
|
+
We combine the notions of [1, 2, 3].
|
|
127
|
+
Motivated by [3], define residuals
|
|
128
|
+
```math
|
|
129
|
+
r_{i, k} =
|
|
130
|
+
\frac{d}{df_{i, k}} \ell(f, y) =
|
|
131
|
+
\begin{cases}
|
|
132
|
+
1 - p_{i, k} & y_i = k \\
|
|
133
|
+
-p_{i, k} & y_i \neq k
|
|
134
|
+
\end{cases}
|
|
135
|
+
```
|
|
136
|
+
such that for all $i$ we have $\sum_{k} r_{i, k} = 0$.
|
|
137
|
+
|
|
138
|
+
For some tuning parameter $\gamma$, we add the regularization term $(\gamma - 1) \| \pi_A r \|_2^2$ to our optimization problem.
|
|
139
|
+
|
|
140
|
+
$$
|
|
141
|
+
\hat f = \underset{f}{\arg \min} \ \ell(f, Y) + (\gamma - 1) \|\pi_A r\|_2^2
|
|
142
|
+
$$
|
|
143
|
+
|
|
144
|
+
This encourages uncorrelatedness between the residuals and the anchor and, hopefully, better domain generalization. To optimize this, we also calculate the gradient of the regularization term. First, note that
|
|
145
|
+
|
|
146
|
+
$$
|
|
147
|
+
\frac{d}{d f_{i, k}} p_{i, j} =
|
|
148
|
+
\frac{d}{d f_{i, k}} \frac{\exp(f_{i, j})}{\sum_l \exp(f_{i, l})} =
|
|
149
|
+
\begin{cases}
|
|
150
|
+
\frac{\exp(f_{i, k})}{\sum_l \exp(f_{i, l})} - \frac{\exp(f_{i, k})^2}{(\sum_l \exp(f_{i, l}))^2} & j = k \\
|
|
151
|
+
-\frac{\exp(f_{i, k})\exp{(f_{i, j})}}{(\sum_l \exp(f_{i, l}))^2} & j \neq k
|
|
152
|
+
\end{cases} =
|
|
153
|
+
\begin{cases}
|
|
154
|
+
p_{i, j} - p_{i, j}p_{i, k} & j = k \\
|
|
155
|
+
-p_{i, j} p_{i, k} & j \neq k
|
|
156
|
+
\end{cases}.
|
|
157
|
+
$$
|
|
158
|
+
|
|
159
|
+
Then,
|
|
160
|
+
|
|
161
|
+
```math
|
|
162
|
+
\frac{d}{d f_{i, k}} \| \pi_A r\|_2^2 = 2 \pi_A r \cdot \left(\begin{cases}
|
|
163
|
+
p_{i, j} - p_{i, j}p_{i, k} & l=i, j = k \\
|
|
164
|
+
-p_{i, j} p_{i, k} & l=i, j \neq k \\
|
|
165
|
+
0 & l \neq i
|
|
166
|
+
\end{cases}\right)_{l=1, \ldots, n}^{j=1, \ldots K}
|
|
167
|
+
=(\pi_A r)_{i, k} \ p_{i, k} - \sum_{l=1}^K (\pi_A r)_{i, l} \ p_{i, l}.
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
<!---
|
|
171
|
+
The diagonal of the hessian is equal to
|
|
172
|
+
|
|
173
|
+
$$
|
|
174
|
+
\frac{d^2}{d f_{i, k}^2} \| \pi_A r\|^2 = 2 \pi_A r \cdot
|
|
175
|
+
\left(\begin{cases}
|
|
176
|
+
p_{i, j} - 3 p_{i, j}^2 + 2 p_{i, j}^3 & l=i, j = k \\
|
|
177
|
+
2 p_{i, j} p_{i, k}^2 - p_{i, j} p{i, k} & l=i, j \neq k \\
|
|
178
|
+
0 & l \neq i
|
|
179
|
+
\end{cases}\right)_{l=1, \ldots, n}^{j=1, \ldots K} +
|
|
180
|
+
2 \pi_A \left(\begin{cases}
|
|
181
|
+
p_{i, j} - p_{i, j}p_{i, k} & l=i, j = k \\
|
|
182
|
+
- p_{i, j} p_{i, k} & l=i, j \neq k \\
|
|
183
|
+
0 & l \neq i
|
|
184
|
+
\end{cases}\right)_{l=1, \ldots, n}^{j=1, \ldots K} \cdot \left(\begin{cases}
|
|
185
|
+
p_{i, j} - p_{i, j}p_{i, k} & l=i, j = k \\
|
|
186
|
+
- p_{i, j} p_{i, k} & l=i, j \neq k \\
|
|
187
|
+
0 & l \neq i
|
|
188
|
+
\end{cases}\right)_{l=1, \ldots, n}^{j=1, \ldots K}
|
|
189
|
+
$$
|
|
190
|
+
|
|
191
|
+
$$
|
|
192
|
+
\frac{d^2}{d f_{i, k} d f_{i, l}} p_{i, j} =
|
|
193
|
+
\begin{cases}
|
|
194
|
+
(1 - 2 p_{i, j}) p_{i, j} (1 - p_{i, j}) & j = k \\
|
|
195
|
+
p_{i, j}^2 p_{i, k} & j \neq k
|
|
196
|
+
\end{cases}
|
|
197
|
+
$$ -->
|
|
198
|
+
|
|
199
|
+
## Anchorized two-class classification with residuals motivated by [4]
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
## References
|
|
204
|
+
|
|
205
|
+
[1] Rothenhäusler, D., N. Meinshausen, P. Bühlmann, and J. Peters (2021). Anchor regression: Heterogeneous data meet causality. Journal of the Royal Statistical Society Series B (Statistical Methodology) 83(2), 215–246.
|
|
206
|
+
|
|
207
|
+
[2] Bühlmann, P. (2020). Invariance, causality and robustness. Statistical Science 35(3), 404– 426.
|
|
208
|
+
|
|
209
|
+
[3] Kook, L., B. Sick, and P. Bühlmann (2022). Distributional anchor regression. Statistics and Computing 32(3), 1–19.
|