deskit 0.3.0__tar.gz → 0.4.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.
- {deskit-0.3.0/src/deskit.egg-info → deskit-0.4.0}/PKG-INFO +28 -27
- {deskit-0.3.0 → deskit-0.4.0}/README.md +27 -26
- {deskit-0.3.0 → deskit-0.4.0}/pyproject.toml +1 -1
- deskit-0.4.0/src/deskit/des/dewst.py +200 -0
- {deskit-0.3.0 → deskit-0.4.0/src/deskit.egg-info}/PKG-INFO +28 -27
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit.egg-info/SOURCES.txt +1 -0
- {deskit-0.3.0 → deskit-0.4.0}/LICENSE +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/setup.cfg +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/__init__.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/_config.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/analysis.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/base/__init__.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/base/base.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/base/knnbase.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/__init__.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/dewsi.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/dewsu.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/knorae.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/knoraiu.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/knorau.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/ola.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/metrics.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/neighbors.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/router.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit/utils.py +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit.egg-info/dependency_links.txt +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit.egg-info/requires.txt +0 -0
- {deskit-0.3.0 → deskit-0.4.0}/src/deskit.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deskit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A Python library for Dynamic Ensemble Selection
|
|
5
5
|
Author: Tikhon Vodyanov
|
|
6
6
|
License-Expression: MIT
|
|
@@ -150,14 +150,15 @@ weights = router.predict(X_test[i])
|
|
|
150
150
|
|
|
151
151
|
## Algorithms
|
|
152
152
|
|
|
153
|
-
| Method
|
|
154
|
-
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
153
|
+
| Method | Best for | Notes |
|
|
154
|
+
|------------|----------------|------------------------------------------------------------------------------------------------------|
|
|
155
|
+
| `DEWS-U` | Regression | Softmax over neighborhood-averaged scores. Temperature controls sharpness. |
|
|
156
|
+
| `DEWS-I` | Regression | Like DEWS-U but scores are inverse-distance weighted. |
|
|
157
|
+
| `DEWS-T` | Both | Like DEWS-U but fits a weighted trend line over neighbor scores and extrapolates to the test point. |
|
|
158
|
+
| `KNORA-U` | Classification | Vote-count weighting. Each model earns one vote per neighbor it correctly classifies. |
|
|
159
|
+
| `KNORA-E` | Classification | Intersection-based. Only models correct on all neighbors survive; falls back to smaller neighborhoods. |
|
|
160
|
+
| `KNORA-IU` | Classification | Like KNORA-U but votes are inverse-distance weighted. |
|
|
161
|
+
| `OLA` | Both | Hard selection: only the single best model in the neighborhood contributes. |
|
|
161
162
|
|
|
162
163
|
---
|
|
163
164
|
|
|
@@ -231,39 +232,39 @@ Pool: KNN, Decision Tree, SVR, Ridge, Bayesian Ridge.
|
|
|
231
232
|
|
|
232
233
|
This pool was selected for having variability in architectures while avoiding a single dominant model.
|
|
233
234
|
|
|
234
|
-
deskit algorithms tested: OLA, DEWS-U, DEWS-I, KNORA-U, KNORA-E, KNORA-IU.
|
|
235
|
+
deskit algorithms tested: OLA, DEWS-U, DEWS-I, DEWS-T, KNORA-U, KNORA-E, KNORA-IU.
|
|
235
236
|
|
|
236
237
|
### Regression (MAE, lower is better)
|
|
237
238
|
|
|
238
|
-
% shown as delta vs Best Single.
|
|
239
|
+
% shown as delta vs Best Single. 20-seed mean.
|
|
239
240
|
|
|
240
|
-
| Dataset | Best Single | Simple Avg | deskit best
|
|
241
|
-
|
|
242
|
-
| California Housing (sklearn) | 0.
|
|
243
|
-
| Bike Sharing (OpenML) | 51.
|
|
244
|
-
| Abalone (OpenML) | **1.
|
|
245
|
-
| Diabetes (sklearn) | **44.
|
|
246
|
-
| Concrete Strength (OpenML) | 5.
|
|
241
|
+
| Dataset | Best Single | Simple Avg | deskit best |
|
|
242
|
+
|------------------------------|-------------|------------|---------------------------|
|
|
243
|
+
| California Housing (sklearn) | 0.3956 | +7.99% | **−2.54%** (DEWS-I) |
|
|
244
|
+
| Bike Sharing (OpenML) | 51.678 | +47.77% | **−6.86%** (DEWS-I) |
|
|
245
|
+
| Abalone (OpenML) | **1.4981** | +1.14% | +1.47% (KNORA-U/KNORA-IU) |
|
|
246
|
+
| Diabetes (sklearn) | **44.504** | +3.18% | +1.09% (DEWS-I/DEWS-T) |
|
|
247
|
+
| Concrete Strength (OpenML) | 5.2686 | +23.66% | **−1.20%** (DEWS-I) |
|
|
247
248
|
|
|
248
249
|
deskit beats best single and simple averaging on 3/5 regression datasets. This shows how DES can provide a
|
|
249
250
|
strong boost if used on the right dataset, but it might be counterproductive if used blindly.
|
|
250
251
|
|
|
251
252
|
KNORA variants are designed for classification, which explains the poor performance
|
|
252
253
|
on regression datasets; However, some exception can occur in certain datasets, either where
|
|
253
|
-
feature space
|
|
254
|
+
feature space has hard clusters (like in Concrete Strength) or when the target is discrete
|
|
254
255
|
and classification-like (like in Abalone).
|
|
255
256
|
|
|
256
257
|
### Classification (Accuracy, higher is better)
|
|
257
258
|
|
|
258
|
-
% shown as delta vs Best Single.
|
|
259
|
+
% shown as delta vs Best Single. 20-seed mean.
|
|
259
260
|
|
|
260
|
-
| Dataset | Best Single | Simple Avg | deskit best
|
|
261
|
-
|
|
262
|
-
| HAR (OpenML) | 98.24% | −0.
|
|
263
|
-
| Yeast (OpenML) |
|
|
264
|
-
| Image Segment (OpenML) | 93.
|
|
265
|
-
| Waveform (OpenML) | **
|
|
266
|
-
| Vowel (OpenML) |
|
|
261
|
+
| Dataset | Best Single | Simple Avg | deskit best |
|
|
262
|
+
|------------------------|-------------|------------|--------------------------|
|
|
263
|
+
| HAR (OpenML) | 98.24% | −0.33% | **+0.16%** (DEWS-T) |
|
|
264
|
+
| Yeast (OpenML) | 58.87% | +0.77% | **+1.66%** (KNORA-IU) |
|
|
265
|
+
| Image Segment (OpenML) | 93.70% | +1.40% | **+2.25%** (DEWS-T) |
|
|
266
|
+
| Waveform (OpenML) | **85.91%** | −0.98% | −0.39% (DEWS-T) |
|
|
267
|
+
| Vowel (OpenML) | 89.95% | −2.05% | **+0.93%** (KNORA-IU) |
|
|
267
268
|
|
|
268
269
|
deskit beats or matches best single and simple averaging on 4/5 classification datasets. As seen on regression, DES
|
|
269
270
|
can improve or hurt performance, so it must be used wisely, but if used correctly it can show promising results.
|
|
@@ -119,14 +119,15 @@ weights = router.predict(X_test[i])
|
|
|
119
119
|
|
|
120
120
|
## Algorithms
|
|
121
121
|
|
|
122
|
-
| Method
|
|
123
|
-
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
122
|
+
| Method | Best for | Notes |
|
|
123
|
+
|------------|----------------|------------------------------------------------------------------------------------------------------|
|
|
124
|
+
| `DEWS-U` | Regression | Softmax over neighborhood-averaged scores. Temperature controls sharpness. |
|
|
125
|
+
| `DEWS-I` | Regression | Like DEWS-U but scores are inverse-distance weighted. |
|
|
126
|
+
| `DEWS-T` | Both | Like DEWS-U but fits a weighted trend line over neighbor scores and extrapolates to the test point. |
|
|
127
|
+
| `KNORA-U` | Classification | Vote-count weighting. Each model earns one vote per neighbor it correctly classifies. |
|
|
128
|
+
| `KNORA-E` | Classification | Intersection-based. Only models correct on all neighbors survive; falls back to smaller neighborhoods. |
|
|
129
|
+
| `KNORA-IU` | Classification | Like KNORA-U but votes are inverse-distance weighted. |
|
|
130
|
+
| `OLA` | Both | Hard selection: only the single best model in the neighborhood contributes. |
|
|
130
131
|
|
|
131
132
|
---
|
|
132
133
|
|
|
@@ -200,39 +201,39 @@ Pool: KNN, Decision Tree, SVR, Ridge, Bayesian Ridge.
|
|
|
200
201
|
|
|
201
202
|
This pool was selected for having variability in architectures while avoiding a single dominant model.
|
|
202
203
|
|
|
203
|
-
deskit algorithms tested: OLA, DEWS-U, DEWS-I, KNORA-U, KNORA-E, KNORA-IU.
|
|
204
|
+
deskit algorithms tested: OLA, DEWS-U, DEWS-I, DEWS-T, KNORA-U, KNORA-E, KNORA-IU.
|
|
204
205
|
|
|
205
206
|
### Regression (MAE, lower is better)
|
|
206
207
|
|
|
207
|
-
% shown as delta vs Best Single.
|
|
208
|
+
% shown as delta vs Best Single. 20-seed mean.
|
|
208
209
|
|
|
209
|
-
| Dataset | Best Single | Simple Avg | deskit best
|
|
210
|
-
|
|
211
|
-
| California Housing (sklearn) | 0.
|
|
212
|
-
| Bike Sharing (OpenML) | 51.
|
|
213
|
-
| Abalone (OpenML) | **1.
|
|
214
|
-
| Diabetes (sklearn) | **44.
|
|
215
|
-
| Concrete Strength (OpenML) | 5.
|
|
210
|
+
| Dataset | Best Single | Simple Avg | deskit best |
|
|
211
|
+
|------------------------------|-------------|------------|---------------------------|
|
|
212
|
+
| California Housing (sklearn) | 0.3956 | +7.99% | **−2.54%** (DEWS-I) |
|
|
213
|
+
| Bike Sharing (OpenML) | 51.678 | +47.77% | **−6.86%** (DEWS-I) |
|
|
214
|
+
| Abalone (OpenML) | **1.4981** | +1.14% | +1.47% (KNORA-U/KNORA-IU) |
|
|
215
|
+
| Diabetes (sklearn) | **44.504** | +3.18% | +1.09% (DEWS-I/DEWS-T) |
|
|
216
|
+
| Concrete Strength (OpenML) | 5.2686 | +23.66% | **−1.20%** (DEWS-I) |
|
|
216
217
|
|
|
217
218
|
deskit beats best single and simple averaging on 3/5 regression datasets. This shows how DES can provide a
|
|
218
219
|
strong boost if used on the right dataset, but it might be counterproductive if used blindly.
|
|
219
220
|
|
|
220
221
|
KNORA variants are designed for classification, which explains the poor performance
|
|
221
222
|
on regression datasets; However, some exception can occur in certain datasets, either where
|
|
222
|
-
feature space
|
|
223
|
+
feature space has hard clusters (like in Concrete Strength) or when the target is discrete
|
|
223
224
|
and classification-like (like in Abalone).
|
|
224
225
|
|
|
225
226
|
### Classification (Accuracy, higher is better)
|
|
226
227
|
|
|
227
|
-
% shown as delta vs Best Single.
|
|
228
|
+
% shown as delta vs Best Single. 20-seed mean.
|
|
228
229
|
|
|
229
|
-
| Dataset | Best Single | Simple Avg | deskit best
|
|
230
|
-
|
|
231
|
-
| HAR (OpenML) | 98.24% | −0.
|
|
232
|
-
| Yeast (OpenML) |
|
|
233
|
-
| Image Segment (OpenML) | 93.
|
|
234
|
-
| Waveform (OpenML) | **
|
|
235
|
-
| Vowel (OpenML) |
|
|
230
|
+
| Dataset | Best Single | Simple Avg | deskit best |
|
|
231
|
+
|------------------------|-------------|------------|--------------------------|
|
|
232
|
+
| HAR (OpenML) | 98.24% | −0.33% | **+0.16%** (DEWS-T) |
|
|
233
|
+
| Yeast (OpenML) | 58.87% | +0.77% | **+1.66%** (KNORA-IU) |
|
|
234
|
+
| Image Segment (OpenML) | 93.70% | +1.40% | **+2.25%** (DEWS-T) |
|
|
235
|
+
| Waveform (OpenML) | **85.91%** | −0.98% | −0.39% (DEWS-T) |
|
|
236
|
+
| Vowel (OpenML) | 89.95% | −2.05% | **+0.93%** (KNORA-IU) |
|
|
236
237
|
|
|
237
238
|
deskit beats or matches best single and simple averaging on 4/5 classification datasets. As seen on regression, DES
|
|
238
239
|
can improve or hurt performance, so it must be used wisely, but if used correctly it can show promising results.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DEWS-T: Distance-weighted Ensemble with Softmax — Trend.
|
|
3
|
+
"""
|
|
4
|
+
from deskit.base.knnbase import KNNBase
|
|
5
|
+
from deskit._config import make_finder, resolve_metric, prep_fit_inputs
|
|
6
|
+
from deskit.utils import to_numpy
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
_SIGNED_METRICS = {'mae', 'mse'}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _signed_residual(y_true, y_pred):
|
|
14
|
+
return float(y_true) - float(y_pred)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DEWST(KNNBase):
|
|
18
|
+
"""
|
|
19
|
+
DEWS-T: Distance-weighted Ensemble with Softmax — Trend.
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
task : str
|
|
23
|
+
'classification' or 'regression'.
|
|
24
|
+
metric : str or callable
|
|
25
|
+
Scoring function. 'mae' or 'mse' activate signed-residual mode;
|
|
26
|
+
all other metrics are trended directly.
|
|
27
|
+
mode : str
|
|
28
|
+
'max' if higher scores are better, 'min' if lower.
|
|
29
|
+
k : int
|
|
30
|
+
Neighbourhood size. Default: 10.
|
|
31
|
+
threshold : float
|
|
32
|
+
Competence gate. After per-neighbourhood normalisation (best=1.0,
|
|
33
|
+
worst=0.0), models below this fraction are excluded from softmax.
|
|
34
|
+
0.0 disables the gate; 1.0 reduces to OLA behaviour. Default: 0.5.
|
|
35
|
+
temperature : float, optional
|
|
36
|
+
Softmax sharpness. Lower = sharper routing toward the local best model.
|
|
37
|
+
Defaults to 0.1 for min-metrics, 1.0 otherwise.
|
|
38
|
+
r2_threshold : float
|
|
39
|
+
Minimum weighted R² for the trend line to be trusted. Below this value
|
|
40
|
+
the sample falls back to DEWS-I scoring for that model. Default: 0.2.
|
|
41
|
+
preset : str
|
|
42
|
+
Neighbour search preset. Default: 'balanced'. See list_presets().
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, task, metric='mae', mode='min', k=10,
|
|
46
|
+
threshold=0.5, temperature=None, r2_threshold=0.2,
|
|
47
|
+
preset='balanced', **kwargs):
|
|
48
|
+
metric_name, metric_fn = resolve_metric(metric)
|
|
49
|
+
finder = make_finder(preset, k, **kwargs)
|
|
50
|
+
|
|
51
|
+
self._use_signed = metric_name in _SIGNED_METRICS
|
|
52
|
+
self._metric_name = metric_name
|
|
53
|
+
self._convert = {'mae': np.abs, 'mse': np.square}.get(metric_name)
|
|
54
|
+
|
|
55
|
+
# For signed metrics, use signed residuals
|
|
56
|
+
super().__init__(
|
|
57
|
+
metric=_signed_residual if self._use_signed else metric_fn,
|
|
58
|
+
mode='max' if self._use_signed else mode,
|
|
59
|
+
neighbor_finder=finder
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
self._real_mode = mode
|
|
63
|
+
self.task = task
|
|
64
|
+
self.threshold = threshold
|
|
65
|
+
self._temperature = temperature
|
|
66
|
+
self.r2_threshold = r2_threshold
|
|
67
|
+
|
|
68
|
+
def fit(self, features, y, preds_dict):
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
features : array-like, shape (n_val, n_features)
|
|
74
|
+
Validation features. Must not overlap with train or test data.
|
|
75
|
+
y : array-like, shape (n_val,)
|
|
76
|
+
Validation ground-truth labels or values.
|
|
77
|
+
preds_dict : dict[str, array-like]
|
|
78
|
+
Validation predictions keyed by model name.
|
|
79
|
+
"""
|
|
80
|
+
features, y, preds_dict = prep_fit_inputs(
|
|
81
|
+
features, y, preds_dict, self._metric_name
|
|
82
|
+
)
|
|
83
|
+
super().fit(features, y, preds_dict)
|
|
84
|
+
|
|
85
|
+
def predict(self, x, temperature=None, threshold=None):
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
x : array-like, shape (n_features,) or (n_samples, n_features)
|
|
91
|
+
temperature : float, optional
|
|
92
|
+
Overrides the instance temperature for this call.
|
|
93
|
+
threshold : float, optional
|
|
94
|
+
Overrides the instance threshold for this call.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
dict or list of dict
|
|
99
|
+
Single sample: {model_name: weight}. Batch: list of such dicts.
|
|
100
|
+
"""
|
|
101
|
+
t = temperature if temperature is not None else (
|
|
102
|
+
self._temperature if self._temperature is not None else
|
|
103
|
+
(0.1 if self._real_mode == 'min' else 1.0))
|
|
104
|
+
th = threshold if threshold is not None else self.threshold
|
|
105
|
+
|
|
106
|
+
x = np.atleast_2d(to_numpy(x))
|
|
107
|
+
batch_size = x.shape[0]
|
|
108
|
+
|
|
109
|
+
distances, indices = self.model.kneighbors(x) # (batch, k)
|
|
110
|
+
k = distances.shape[1]
|
|
111
|
+
|
|
112
|
+
# Inverse-distance weights
|
|
113
|
+
inv_dist = 1.0 / np.maximum(distances, 1e-8) # (batch, k)
|
|
114
|
+
inv_dist_w = inv_dist / inv_dist.sum(axis=1, keepdims=True)
|
|
115
|
+
|
|
116
|
+
# Scores at each neighbour: (batch, k, n_models).
|
|
117
|
+
neighbor_scores = self.matrix[indices]
|
|
118
|
+
|
|
119
|
+
# Weighted least squares trend
|
|
120
|
+
d_max = distances.max(axis=1, keepdims=True)
|
|
121
|
+
d_norm = distances / np.where(d_max > 0, d_max, 1.0) # (batch, k)
|
|
122
|
+
|
|
123
|
+
# X^{T}WX: shape (batch, 2, 2)
|
|
124
|
+
W = inv_dist_w # (batch, k)
|
|
125
|
+
a = W.sum(axis=1) # (batch,)
|
|
126
|
+
b = (W * d_norm).sum(axis=1)
|
|
127
|
+
d_v = (W * d_norm ** 2).sum(axis=1)
|
|
128
|
+
det = a * d_v - b ** 2 # (batch,)
|
|
129
|
+
bad_det = np.abs(det) <= 1e-12
|
|
130
|
+
det_safe = np.where(bad_det, 1.0, det)
|
|
131
|
+
|
|
132
|
+
# XᵀWy for all models: shape (batch, 2, n_models).
|
|
133
|
+
Wy = neighbor_scores * inv_dist_w[:, :, np.newaxis] # (batch, k, n_models)
|
|
134
|
+
Wdy = Wy * d_norm[:, :, np.newaxis]
|
|
135
|
+
XtWy_0 = Wy.sum(axis=1) # (batch, n_models)
|
|
136
|
+
XtWy_1 = Wdy.sum(axis=1) # (batch, n_models)
|
|
137
|
+
|
|
138
|
+
# Closed-form 2×2 inverse applied.
|
|
139
|
+
# intercept B0
|
|
140
|
+
# slope B1
|
|
141
|
+
intercept = (d_v[:, np.newaxis] * XtWy_0 -
|
|
142
|
+
b[:, np.newaxis] * XtWy_1) / det_safe[:, np.newaxis]
|
|
143
|
+
slope = (a[:, np.newaxis] * XtWy_1 -
|
|
144
|
+
b[:, np.newaxis] * XtWy_0) / det_safe[:, np.newaxis]
|
|
145
|
+
|
|
146
|
+
# Weighted R^2
|
|
147
|
+
y_hat = (intercept[:, np.newaxis, :] +
|
|
148
|
+
slope[:, np.newaxis, :] *
|
|
149
|
+
d_norm[:, :, np.newaxis]) # (batch, k, n_models)
|
|
150
|
+
y_wmean = XtWy_0 # weighted mean
|
|
151
|
+
ss_res = (inv_dist_w[:, :, np.newaxis] *
|
|
152
|
+
(neighbor_scores - y_hat) ** 2).sum(axis=1)
|
|
153
|
+
ss_tot = (inv_dist_w[:, :, np.newaxis] *
|
|
154
|
+
(neighbor_scores - y_wmean[:, np.newaxis, :]) ** 2).sum(axis=1)
|
|
155
|
+
r2 = np.where(ss_tot > 1e-12, 1.0 - ss_res / ss_tot, 0.0)
|
|
156
|
+
# Bad determinant = fallback.
|
|
157
|
+
r2 = np.where(bad_det[:, np.newaxis], 0.0, r2) # (batch, n_models)
|
|
158
|
+
|
|
159
|
+
# DEWS-I fallback
|
|
160
|
+
if self._use_signed:
|
|
161
|
+
# Convert signed residuals back to metric
|
|
162
|
+
fallback_raw = self._convert(neighbor_scores)
|
|
163
|
+
dewsi_scores = -(fallback_raw * inv_dist_w[:, :, np.newaxis]).sum(axis=1)
|
|
164
|
+
else:
|
|
165
|
+
dewsi_scores = XtWy_0
|
|
166
|
+
|
|
167
|
+
# Convert trend intercept to routing scord
|
|
168
|
+
if self._use_signed:
|
|
169
|
+
trend_scores = -self._convert(intercept) # negate for min-routing
|
|
170
|
+
else:
|
|
171
|
+
trend_scores = intercept
|
|
172
|
+
|
|
173
|
+
# Blend: trust trend where R² ≥ threshold, fall back otherwise.
|
|
174
|
+
use_trend = r2 >= self.r2_threshold
|
|
175
|
+
avg_scores = np.where(use_trend, trend_scores, dewsi_scores)
|
|
176
|
+
|
|
177
|
+
# Standard DEWS softmax
|
|
178
|
+
local_min = avg_scores.min(axis=1, keepdims=True)
|
|
179
|
+
local_max = avg_scores.max(axis=1, keepdims=True)
|
|
180
|
+
local_range = local_max - local_min
|
|
181
|
+
norm_scores = (avg_scores - local_min) / np.where(local_range > 0, local_range, 1.0)
|
|
182
|
+
|
|
183
|
+
if th > 0:
|
|
184
|
+
gate = norm_scores >= th
|
|
185
|
+
any_pass = gate.any(axis=1, keepdims=True)
|
|
186
|
+
gate = np.where(any_pass, gate, norm_scores == 1.0)
|
|
187
|
+
norm_scores = norm_scores * gate
|
|
188
|
+
|
|
189
|
+
max_scores = norm_scores.max(axis=1, keepdims=True)
|
|
190
|
+
exp_scores = np.exp((norm_scores - max_scores) / t)
|
|
191
|
+
if th > 0:
|
|
192
|
+
exp_scores = exp_scores * gate
|
|
193
|
+
total = exp_scores.sum(axis=1, keepdims=True)
|
|
194
|
+
weights = np.where(total > 0,
|
|
195
|
+
exp_scores / np.where(total > 0, total, 1.0),
|
|
196
|
+
np.full_like(exp_scores, 1.0 / len(self.models)))
|
|
197
|
+
|
|
198
|
+
if batch_size == 1:
|
|
199
|
+
return dict(zip(self.models, weights[0]))
|
|
200
|
+
return [dict(zip(self.models, w)) for w in weights]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deskit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A Python library for Dynamic Ensemble Selection
|
|
5
5
|
Author: Tikhon Vodyanov
|
|
6
6
|
License-Expression: MIT
|
|
@@ -150,14 +150,15 @@ weights = router.predict(X_test[i])
|
|
|
150
150
|
|
|
151
151
|
## Algorithms
|
|
152
152
|
|
|
153
|
-
| Method
|
|
154
|
-
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
153
|
+
| Method | Best for | Notes |
|
|
154
|
+
|------------|----------------|------------------------------------------------------------------------------------------------------|
|
|
155
|
+
| `DEWS-U` | Regression | Softmax over neighborhood-averaged scores. Temperature controls sharpness. |
|
|
156
|
+
| `DEWS-I` | Regression | Like DEWS-U but scores are inverse-distance weighted. |
|
|
157
|
+
| `DEWS-T` | Both | Like DEWS-U but fits a weighted trend line over neighbor scores and extrapolates to the test point. |
|
|
158
|
+
| `KNORA-U` | Classification | Vote-count weighting. Each model earns one vote per neighbor it correctly classifies. |
|
|
159
|
+
| `KNORA-E` | Classification | Intersection-based. Only models correct on all neighbors survive; falls back to smaller neighborhoods. |
|
|
160
|
+
| `KNORA-IU` | Classification | Like KNORA-U but votes are inverse-distance weighted. |
|
|
161
|
+
| `OLA` | Both | Hard selection: only the single best model in the neighborhood contributes. |
|
|
161
162
|
|
|
162
163
|
---
|
|
163
164
|
|
|
@@ -231,39 +232,39 @@ Pool: KNN, Decision Tree, SVR, Ridge, Bayesian Ridge.
|
|
|
231
232
|
|
|
232
233
|
This pool was selected for having variability in architectures while avoiding a single dominant model.
|
|
233
234
|
|
|
234
|
-
deskit algorithms tested: OLA, DEWS-U, DEWS-I, KNORA-U, KNORA-E, KNORA-IU.
|
|
235
|
+
deskit algorithms tested: OLA, DEWS-U, DEWS-I, DEWS-T, KNORA-U, KNORA-E, KNORA-IU.
|
|
235
236
|
|
|
236
237
|
### Regression (MAE, lower is better)
|
|
237
238
|
|
|
238
|
-
% shown as delta vs Best Single.
|
|
239
|
+
% shown as delta vs Best Single. 20-seed mean.
|
|
239
240
|
|
|
240
|
-
| Dataset | Best Single | Simple Avg | deskit best
|
|
241
|
-
|
|
242
|
-
| California Housing (sklearn) | 0.
|
|
243
|
-
| Bike Sharing (OpenML) | 51.
|
|
244
|
-
| Abalone (OpenML) | **1.
|
|
245
|
-
| Diabetes (sklearn) | **44.
|
|
246
|
-
| Concrete Strength (OpenML) | 5.
|
|
241
|
+
| Dataset | Best Single | Simple Avg | deskit best |
|
|
242
|
+
|------------------------------|-------------|------------|---------------------------|
|
|
243
|
+
| California Housing (sklearn) | 0.3956 | +7.99% | **−2.54%** (DEWS-I) |
|
|
244
|
+
| Bike Sharing (OpenML) | 51.678 | +47.77% | **−6.86%** (DEWS-I) |
|
|
245
|
+
| Abalone (OpenML) | **1.4981** | +1.14% | +1.47% (KNORA-U/KNORA-IU) |
|
|
246
|
+
| Diabetes (sklearn) | **44.504** | +3.18% | +1.09% (DEWS-I/DEWS-T) |
|
|
247
|
+
| Concrete Strength (OpenML) | 5.2686 | +23.66% | **−1.20%** (DEWS-I) |
|
|
247
248
|
|
|
248
249
|
deskit beats best single and simple averaging on 3/5 regression datasets. This shows how DES can provide a
|
|
249
250
|
strong boost if used on the right dataset, but it might be counterproductive if used blindly.
|
|
250
251
|
|
|
251
252
|
KNORA variants are designed for classification, which explains the poor performance
|
|
252
253
|
on regression datasets; However, some exception can occur in certain datasets, either where
|
|
253
|
-
feature space
|
|
254
|
+
feature space has hard clusters (like in Concrete Strength) or when the target is discrete
|
|
254
255
|
and classification-like (like in Abalone).
|
|
255
256
|
|
|
256
257
|
### Classification (Accuracy, higher is better)
|
|
257
258
|
|
|
258
|
-
% shown as delta vs Best Single.
|
|
259
|
+
% shown as delta vs Best Single. 20-seed mean.
|
|
259
260
|
|
|
260
|
-
| Dataset | Best Single | Simple Avg | deskit best
|
|
261
|
-
|
|
262
|
-
| HAR (OpenML) | 98.24% | −0.
|
|
263
|
-
| Yeast (OpenML) |
|
|
264
|
-
| Image Segment (OpenML) | 93.
|
|
265
|
-
| Waveform (OpenML) | **
|
|
266
|
-
| Vowel (OpenML) |
|
|
261
|
+
| Dataset | Best Single | Simple Avg | deskit best |
|
|
262
|
+
|------------------------|-------------|------------|--------------------------|
|
|
263
|
+
| HAR (OpenML) | 98.24% | −0.33% | **+0.16%** (DEWS-T) |
|
|
264
|
+
| Yeast (OpenML) | 58.87% | +0.77% | **+1.66%** (KNORA-IU) |
|
|
265
|
+
| Image Segment (OpenML) | 93.70% | +1.40% | **+2.25%** (DEWS-T) |
|
|
266
|
+
| Waveform (OpenML) | **85.91%** | −0.98% | −0.39% (DEWS-T) |
|
|
267
|
+
| Vowel (OpenML) | 89.95% | −2.05% | **+0.93%** (KNORA-IU) |
|
|
267
268
|
|
|
268
269
|
deskit beats or matches best single and simple averaging on 4/5 classification datasets. As seen on regression, DES
|
|
269
270
|
can improve or hurt performance, so it must be used wisely, but if used correctly it can show promising results.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|