Skip to content

Commit 7c7dc92

Browse files
committed
_
1 parent 1f7694c commit 7c7dc92

1 file changed

Lines changed: 14 additions & 15 deletions

File tree

skrub/_data_ops/_estimator.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -928,43 +928,42 @@ def _score(self, X, y=None, cast_to_float=True, return_predictions=False):
928928
score_node._skrub_impl.scorers, mode="fit_transform", environment=env
929929
)
930930
all_scores = []
931-
predictions = env.get("_skrub_predictions", {})
932-
cache = {(k, id(X)): v for k, v in predictions.items()}
931+
cache = dict(env.get("_skrub_predictions", {}))
933932
caching_estimator = _CachingXyPipeline(
934-
self.data_op, self.environment, cache=cache
933+
self.data_op, self.environment, X_id=id(X), cache=cache
935934
)
936935
_copy_attr(self, caching_estimator, ["_is_fitted"])
937936
for scorer_info in scorers:
938937
scorer = self._prepare_scorer(scorer_info["scoring"], scorer_info["kwargs"])
939938
scorer_output = scorer(caching_estimator, X, y)
940939
all_scores.extend(self._process_scores(scorer_info, scorer_output))
941-
updated_predictions = {
942-
k: v for ((k, X_id), v) in cache.items() if X_id == id(X)
943-
}
944940
rename = unique_renaming()
945941
result = {rename(name): score for name, score in all_scores}
946942
if cast_to_float and len(result) == 1 and not return_predictions:
947943
# If there is a single score stick to scikit-learn interface which
948944
# returns a number.
949945
return next(iter(result.values()))
950-
return (result, updated_predictions) if return_predictions else result
946+
return (result, caching_estimator.cache) if return_predictions else result
951947

952948

953949
class _CachingXyPipeline(_XyPipeline):
954-
def __init__(self, data_op, environment, cache):
950+
def __init__(self, data_op, environment, X_id, cache):
955951
super().__init__(data_op, environment)
952+
self.X_id = X_id
956953
self.cache = cache
957954

958955
def _eval_in_mode(self, mode, X, y=None):
959-
if y is not None:
956+
if y is not None or id(X) != self.X_id:
960957
# Only use caching for methods like predict, predict_proba etc.
961-
# (They are the only ones to be called anyway unless a scorer does
962-
# something very weird)
958+
# (for which y is None), and when they are called on the "main" X,
959+
# the X that was passed to SkrubLearner.score . For example if a
960+
# scorer computes a metric on a subsample of the dataset (e.g. a
961+
# group for fairness etc.), we do not use the cached result for
962+
# that different input.
963963
return super()._eval_in_mode(mode, X, y=y)
964-
key = (mode, id(X))
965-
if key not in self.cache:
966-
self.cache[key] = super()._eval_in_mode(mode, X, y=y)
967-
return self.cache[key]
964+
if mode not in self.cache:
965+
self.cache[mode] = super()._eval_in_mode(mode, X, y=y)
966+
return self.cache[mode]
968967

969968
def _score(self, X, y=None):
970969
# If a scorer calls score(), eval in "score" mode (i.e. ignoring

0 commit comments

Comments
 (0)