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.
Files changed (28) hide show
  1. {deskit-0.3.0/src/deskit.egg-info → deskit-0.4.0}/PKG-INFO +28 -27
  2. {deskit-0.3.0 → deskit-0.4.0}/README.md +27 -26
  3. {deskit-0.3.0 → deskit-0.4.0}/pyproject.toml +1 -1
  4. deskit-0.4.0/src/deskit/des/dewst.py +200 -0
  5. {deskit-0.3.0 → deskit-0.4.0/src/deskit.egg-info}/PKG-INFO +28 -27
  6. {deskit-0.3.0 → deskit-0.4.0}/src/deskit.egg-info/SOURCES.txt +1 -0
  7. {deskit-0.3.0 → deskit-0.4.0}/LICENSE +0 -0
  8. {deskit-0.3.0 → deskit-0.4.0}/setup.cfg +0 -0
  9. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/__init__.py +0 -0
  10. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/_config.py +0 -0
  11. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/analysis.py +0 -0
  12. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/base/__init__.py +0 -0
  13. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/base/base.py +0 -0
  14. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/base/knnbase.py +0 -0
  15. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/__init__.py +0 -0
  16. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/dewsi.py +0 -0
  17. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/dewsu.py +0 -0
  18. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/knorae.py +0 -0
  19. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/knoraiu.py +0 -0
  20. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/knorau.py +0 -0
  21. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/des/ola.py +0 -0
  22. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/metrics.py +0 -0
  23. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/neighbors.py +0 -0
  24. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/router.py +0 -0
  25. {deskit-0.3.0 → deskit-0.4.0}/src/deskit/utils.py +0 -0
  26. {deskit-0.3.0 → deskit-0.4.0}/src/deskit.egg-info/dependency_links.txt +0 -0
  27. {deskit-0.3.0 → deskit-0.4.0}/src/deskit.egg-info/requires.txt +0 -0
  28. {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.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 | Best for | Notes |
154
- |-----------|---|----------------------------------------------------------------------------------------------------------|
155
- | `DEWSU` | Regression | Softmax over neighbourhood-averaged scores. Temperature controls sharpness. |
156
- | `DEWSI` | Regression | Like DEWS-U but scores are inverse-distance weighted. |
157
- | `KNORAU` | Classification | Vote-count weighting. Each model earns one vote per neighbour it correctly classifies. |
158
- | `KNORAE` | Classification | Intersection-based. Only models correct on all neighbours survive; falls back to smaller neighbourhoods. |
159
- | `KNORAIU` | Classification | Like KNORA-U but votes are inverse-distance weighted. |
160
- | `OLA` | Both | Hard selection: only the single best model in the neighbourhood contributes. |
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. 100-seed mean.
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.3955 | +7.93% | **−2.68%** (DEWS-I) |
243
- | Bike Sharing (OpenML) | 51.604 | +48.39% | **−6.25%** (DEWS-I) |
244
- | Abalone (OpenML) | **1.4923** | +1.29% | +1.61% (KNORA-IU) |
245
- | Diabetes (sklearn) | **44.986** | +2.98% | +0.88% (DEWS-I) |
246
- | Concrete Strength (OpenML) | 5.3934 | +21.30% | **−2.85%** (KNORA-IU) |
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 is has hard clusters (like in Concrete Strength) or when the target is discrete
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. 100-seed mean.
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.32% | **+0.14%** (DEWS-I) |
263
- | Yeast (OpenML) | 59.19% | +0.46% | **+1.48%** (KNORA-IU) |
264
- | Image Segment (OpenML) | 93.65% | +1.70% | **+2.33%** (KNORA-IU) |
265
- | Waveform (OpenML) | **86.28%** | −1.04% | −0.55% (DEWS-I) |
266
- | Vowel (OpenML) | 90.54% | −1.81% | **+0.93%** (KNORA-IU) |
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 | Best for | Notes |
123
- |-----------|---|----------------------------------------------------------------------------------------------------------|
124
- | `DEWSU` | Regression | Softmax over neighbourhood-averaged scores. Temperature controls sharpness. |
125
- | `DEWSI` | Regression | Like DEWS-U but scores are inverse-distance weighted. |
126
- | `KNORAU` | Classification | Vote-count weighting. Each model earns one vote per neighbour it correctly classifies. |
127
- | `KNORAE` | Classification | Intersection-based. Only models correct on all neighbours survive; falls back to smaller neighbourhoods. |
128
- | `KNORAIU` | Classification | Like KNORA-U but votes are inverse-distance weighted. |
129
- | `OLA` | Both | Hard selection: only the single best model in the neighbourhood contributes. |
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. 100-seed mean.
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.3955 | +7.93% | **−2.68%** (DEWS-I) |
212
- | Bike Sharing (OpenML) | 51.604 | +48.39% | **−6.25%** (DEWS-I) |
213
- | Abalone (OpenML) | **1.4923** | +1.29% | +1.61% (KNORA-IU) |
214
- | Diabetes (sklearn) | **44.986** | +2.98% | +0.88% (DEWS-I) |
215
- | Concrete Strength (OpenML) | 5.3934 | +21.30% | **−2.85%** (KNORA-IU) |
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 is has hard clusters (like in Concrete Strength) or when the target is discrete
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. 100-seed mean.
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.32% | **+0.14%** (DEWS-I) |
232
- | Yeast (OpenML) | 59.19% | +0.46% | **+1.48%** (KNORA-IU) |
233
- | Image Segment (OpenML) | 93.65% | +1.70% | **+2.33%** (KNORA-IU) |
234
- | Waveform (OpenML) | **86.28%** | −1.04% | −0.55% (DEWS-I) |
235
- | Vowel (OpenML) | 90.54% | −1.81% | **+0.93%** (KNORA-IU) |
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.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "deskit"
7
- version = "0.3.0"
7
+ version = "0.4.0"
8
8
  description = "A Python library for Dynamic Ensemble Selection"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -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.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 | Best for | Notes |
154
- |-----------|---|----------------------------------------------------------------------------------------------------------|
155
- | `DEWSU` | Regression | Softmax over neighbourhood-averaged scores. Temperature controls sharpness. |
156
- | `DEWSI` | Regression | Like DEWS-U but scores are inverse-distance weighted. |
157
- | `KNORAU` | Classification | Vote-count weighting. Each model earns one vote per neighbour it correctly classifies. |
158
- | `KNORAE` | Classification | Intersection-based. Only models correct on all neighbours survive; falls back to smaller neighbourhoods. |
159
- | `KNORAIU` | Classification | Like KNORA-U but votes are inverse-distance weighted. |
160
- | `OLA` | Both | Hard selection: only the single best model in the neighbourhood contributes. |
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. 100-seed mean.
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.3955 | +7.93% | **−2.68%** (DEWS-I) |
243
- | Bike Sharing (OpenML) | 51.604 | +48.39% | **−6.25%** (DEWS-I) |
244
- | Abalone (OpenML) | **1.4923** | +1.29% | +1.61% (KNORA-IU) |
245
- | Diabetes (sklearn) | **44.986** | +2.98% | +0.88% (DEWS-I) |
246
- | Concrete Strength (OpenML) | 5.3934 | +21.30% | **−2.85%** (KNORA-IU) |
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 is has hard clusters (like in Concrete Strength) or when the target is discrete
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. 100-seed mean.
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.32% | **+0.14%** (DEWS-I) |
263
- | Yeast (OpenML) | 59.19% | +0.46% | **+1.48%** (KNORA-IU) |
264
- | Image Segment (OpenML) | 93.65% | +1.70% | **+2.33%** (KNORA-IU) |
265
- | Waveform (OpenML) | **86.28%** | −1.04% | −0.55% (DEWS-I) |
266
- | Vowel (OpenML) | 90.54% | −1.81% | **+0.93%** (KNORA-IU) |
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.
@@ -18,6 +18,7 @@ src/deskit/base/base.py
18
18
  src/deskit/base/knnbase.py
19
19
  src/deskit/des/__init__.py
20
20
  src/deskit/des/dewsi.py
21
+ src/deskit/des/dewst.py
21
22
  src/deskit/des/dewsu.py
22
23
  src/deskit/des/knorae.py
23
24
  src/deskit/des/knoraiu.py
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