Skip to content

Commit c4ed24e

Browse files
Ashley Scillitoearnaudvl
andauthored
Copy of "ClassifierDrift bugfix #658", rebased for patch release (#662)
* Fix issue with returned probs_sort when train_size is used * Update CHANGELOG.md Co-authored-by: Arnaud Van Looveren <[email protected]>
1 parent e7cdbcf commit c4ed24e

File tree

5 files changed

+14
-14
lines changed

5 files changed

+14
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
### Fixed
88
- Fixed an incorrect default value for the `alternative` kwarg in the `FETDrift` detector ([#661](https://github.com/SeldonIO/alibi-detect/pull/661)).
9+
- Fixed an issue with `ClassifierDrift` returning incorrect prediction probabilities when `train_size` given ([#662](https://github.com/SeldonIO/alibi-detect/pull/662)).
910

1011
## v0.10.3
1112
## [v0.10.3](https://github.com/SeldonIO/alibi-detect/tree/v0.10.3) (2022-08-17)

alibi_detect/cd/base.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,13 @@ def preprocess(self, x: Union[np.ndarray, list]) -> Tuple[Union[np.ndarray, list
153153
else:
154154
return self.x_ref, x # type: ignore[return-value]
155155

156-
def get_splits(self,
157-
x_ref: Union[np.ndarray, list],
158-
x: Union[np.ndarray, list],
159-
return_splits: bool = True
160-
) -> Union[
161-
Tuple[Union[np.ndarray, list], np.ndarray],
162-
Tuple[Union[np.ndarray, list], np.ndarray, Optional[List[Tuple[np.ndarray, np.ndarray]]]]
163-
]:
156+
def get_splits(
157+
self,
158+
x_ref: Union[np.ndarray, list],
159+
x: Union[np.ndarray, list],
160+
return_splits: bool = True
161+
) -> Union[Tuple[Union[np.ndarray, list], np.ndarray],
162+
Tuple[Union[np.ndarray, list], np.ndarray, Optional[List[Tuple[np.ndarray, np.ndarray]]]]]:
164163
"""
165164
Split reference and test data in train and test folds used by the classifier.
166165

alibi_detect/cd/pytorch/classifier.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,6 @@ def score(self, x: Union[np.ndarray, list]) -> Tuple[float, float, np.ndarray, n
173173
and the out-of-fold classifier model prediction probabilities on the reference and test data
174174
"""
175175
x_ref, x = self.preprocess(x)
176-
n_ref, n_cur = len(x_ref), len(x)
177176
x, y, splits = self.get_splits(x_ref, x) # type: ignore
178177

179178
# iterate over folds: train a new model for each fold and make out-of-fold (oof) predictions
@@ -199,6 +198,8 @@ def score(self, x: Union[np.ndarray, list]) -> Tuple[float, float, np.ndarray, n
199198
probs_oof = softmax(preds_oof, axis=-1) if self.preds_type == 'logits' else preds_oof
200199
idx_oof = np.concatenate(idx_oof_list, axis=0)
201200
y_oof = y[idx_oof]
201+
n_cur = y_oof.sum()
202+
n_ref = len(y_oof) - n_cur
202203
p_val, dist = self.test_probs(y_oof, probs_oof, n_ref, n_cur)
203204
probs_sort = probs_oof[np.argsort(idx_oof)]
204205
return p_val, dist, probs_sort[:n_ref, 1], probs_sort[n_ref:, 1]

alibi_detect/cd/sklearn/classifier.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,29 +251,27 @@ def score(self, x: Union[np.ndarray, list]) -> Tuple[float, float, np.ndarray, n
251251

252252
def _score(self, x: Union[np.ndarray, list]) -> Tuple[float, float, np.ndarray, np.ndarray]:
253253
x_ref, x = self.preprocess(x)
254-
n_ref, n_cur = len(x_ref), len(x)
255254
x, y, splits = self.get_splits(x_ref, x, return_splits=True) # type: ignore
256255

257256
# iterate over folds: train a new model for each fold and make out-of-fold (oof) predictions
258257
probs_oof_list, idx_oof_list = [], []
259258
for idx_tr, idx_te in splits:
260259
y_tr = y[idx_tr]
261-
262260
if isinstance(x, np.ndarray):
263261
x_tr, x_te = x[idx_tr], x[idx_te]
264262
elif isinstance(x, list):
265263
x_tr, x_te = [x[_] for _ in idx_tr], [x[_] for _ in idx_te]
266264
else:
267265
raise TypeError(f'x needs to be of type np.ndarray or list and not {type(x)}.')
268-
269266
self.model.fit(x_tr, y_tr)
270267
probs = self.model.aux_predict_proba(x_te)
271268
probs_oof_list.append(probs)
272269
idx_oof_list.append(idx_te)
273-
274270
probs_oof = np.concatenate(probs_oof_list, axis=0)
275271
idx_oof = np.concatenate(idx_oof_list, axis=0)
276272
y_oof = y[idx_oof]
273+
n_cur = y_oof.sum()
274+
n_ref = len(y_oof) - n_cur
277275
p_val, dist = self.test_probs(y_oof, probs_oof, n_ref, n_cur)
278276
probs_sort = probs_oof[np.argsort(idx_oof)]
279277
return p_val, dist, probs_sort[:n_ref, 1], probs_sort[n_ref:, 1]

alibi_detect/cd/tensorflow/classifier.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ def score(self, x: np.ndarray) -> Tuple[float, float, np.ndarray, np.ndarray]:
160160
and the out-of-fold classifier model prediction probabilities on the reference and test data
161161
"""
162162
x_ref, x = self.preprocess(x) # type: ignore[assignment]
163-
n_ref, n_cur = len(x_ref), len(x)
164163
x, y, splits = self.get_splits(x_ref, x) # type: ignore
165164

166165
# iterate over folds: train a new model for each fold and make out-of-fold (oof) predictions
@@ -186,6 +185,8 @@ def score(self, x: np.ndarray) -> Tuple[float, float, np.ndarray, np.ndarray]:
186185
probs_oof = softmax(preds_oof, axis=-1) if self.preds_type == 'logits' else preds_oof
187186
idx_oof = np.concatenate(idx_oof_list, axis=0)
188187
y_oof = y[idx_oof]
188+
n_cur = y_oof.sum()
189+
n_ref = len(y_oof) - n_cur
189190
p_val, dist = self.test_probs(y_oof, probs_oof, n_ref, n_cur)
190191
probs_sort = probs_oof[np.argsort(idx_oof)]
191192
return p_val, dist, probs_sort[:n_ref, 1], probs_sort[n_ref:, 1]

0 commit comments

Comments
 (0)