[Bug] `predict_model` silently drops `Anomaly_Score` for bare estimators because `decision_function` uses raw `X`
Describe the bug
In PyCaret 4.0's predict_model implementation within experiment.py, there is a bug affecting anomaly detection tasks when a bare estimator (rather than a Pipeline) is passed in.
The method correctly identifies if preprocessing is needed for a bare estimator and transforms X into X_for_pred:
if preprocessor is not None and not estimator_is_pipeline:
# Transform X through the legacy preprocessing chain first.
X_for_pred = preprocessor.transform(X)
else:
X_for_pred = X
preds = np.asarray(estimator.predict(X_for_pred))However, when generating the Anomaly_Score column, it incorrectly passes the raw, un-preprocessed X to the decision_function:
elif self.task == TaskType.ANOMALY:
out["Anomaly"] = preds
if hasattr(estimator, "decision_function"):
try:
out["Anomaly_Score"] = estimator.decision_function(X) # <-- BUG: Should be X_for_pred
except Exception: # pragma: no cover — defensive
passBecause decision_function receives the raw X (which may contain categorical variables, NaNs, etc.), it will throw an exception that gets silently swallowed by the try...except Exception: pass block. As a result, the user silently does not get the Anomaly_Score column in their predictions.
Expected Behavior
The anomaly score calculation should use X_for_pred:
out["Anomaly_Score"] = estimator.decision_function(X_for_pred)This mirrors how classification handles predict_proba:
proba = estimator.predict_proba(X_for_pred)Reproduction Steps
from pycaret.datasets import get_data
from pycaret.tasks import AnomalyExperiment
from sklearn.ensemble import IsolationForest
df = get_data("anomaly")
exp = AnomalyExperiment(session_id=42, preprocess=True).fit(df)
# Train a bare estimator on the transformed data
X_transformed = exp._fit_state["X_transformed"]
model = IsolationForest(random_state=42).fit(X_transformed)
# Predict using the bare estimator
preds = exp.predict_model(model, data=df)
# Anomaly_Score is missing because decision_function failed on raw 'df' and was silently suppressed
print("Anomaly_Score" in preds.columns) Additional context
This bug is present in packages/engine/pycaret/core/experiment.py around line 1625.
Source: pycaret/pycaret