Advanced Features¶
This page covers advanced Lazy Predict capabilities beyond the basic benchmarking workflow.
Hyperparameter Tuning¶
After benchmarking, automatically tune the top-k models using Optuna, scikit-learn, or FLAML.
Installation¶
Supervised Models¶
from lazypredict.Supervised import LazyClassifier
clf = LazyClassifier(
verbose=1,
tune=True,
tune_top_k=5, # tune the 5 best models
tune_trials=50, # 50 Optuna trials per model
tune_timeout=120, # max 2 minutes per model (no new trial starts after it)
tune_backend="optuna", # "optuna", "sklearn", or "flaml"
)
models, predictions = clf.fit(X_train, X_test, y_train, y_test)
# One row per tuned model: "Best Score" (mean cross-validated score on the
# training data, higher is better), "Best Params" (a dict) and "Status"
print(clf.tuned_scores_)
# Models whose tuning succeeded: best hyperparameters and the pipeline refitted with them
for name, pipeline in clf.tuned_models_.items():
print(name, clf.tuned_params_[name])
# predict() and explain() use the tuned models with tuned=True, and convert
# NumPy input to the training columns as for the benchmarked models
clf.predict(X_test, tuned=True)
clf.explain(X_test, y_test, tuned=True)
Tuning is reproducible for a given random_state, uses cv folds (5 when cv
is not set), and a model that cannot be tuned is reported in the Status
column instead of aborting the others. Models without a search space (for
example LassoCV, which tunes its own regularisation) are listed as
"no search space".
Time Series¶
from lazypredict.TimeSeriesForecasting import LazyForecaster
fcst = LazyForecaster(
tune=True,
tune_top_k=3,
tune_trials=30,
tune_metric="RMSE", # "RMSE", "MAE", "MAPE", "SMAPE", "MASE"
tune_seasonal=False, # also search over seasonal_period
)
scores, predictions = fcst.fit(y_train, y_test)
# "Best RMSE" (mean temporal-CV error, lower is better), "Best Params", "Status"
print(fcst.tuned_scores_)
fcst.tuned_models_ # {name: forecaster refitted with the best parameters} for the tuned models
Using the Tuning API Directly¶
from sklearn.ensemble import RandomForestClassifier
from lazypredict.preprocessing import build_preprocessor, prepare_dataframes
from lazypredict.tuning import tune_supervised_optuna
X_train_df, X_test_df = prepare_dataframes(X_train, X_test)
preprocessor = build_preprocessor(X_train_df, categorical_encoder="onehot")
best_params, best_score = tune_supervised_optuna(
"RandomForestClassifier",
RandomForestClassifier,
X_train_df,
y_train,
preprocessor,
scoring="balanced_accuracy",
cv=5,
n_trials=100,
)
tune_supervised_sklearn (RandomizedSearchCV) and tune_supervised_flaml
take the same leading arguments.
Explainability¶
Compute feature importance for all benchmarked models.
Installation¶
Permutation Importance (no extra dependencies)¶
from lazypredict.Supervised import LazyRegressor
reg = LazyRegressor(verbose=0, ignore_warnings=True)
models, predictions = reg.fit(X_train, X_test, y_train, y_test)
# Features as rows, models as columns
importance_df = reg.explain(X_test, y_test, method="permutation", n_repeats=10)
print(importance_df)
SHAP Values¶
# {model name: SHAP values for the transformed features}
shap_values = reg.explain(X_test, y_test, method="shap", max_samples=100)
shap_values["RandomForestRegressor"].shape # (n_samples, n_features)
Binary classifiers return the values of the positive class; multiclass
classifiers return an array of shape (n_samples, n_features, n_classes).
The lower-level lazypredict.explainability.explain_shap(models, X_test,
step_name="regressor") takes the dict of fitted pipelines (reg.models).
InterpretML (EBM)¶
When interpret is installed, ExplainableBoostingClassifier and
ExplainableBoostingRegressor are automatically included in benchmarking.
These are inherently interpretable glass-box models.
Time Series Visualization¶
Requires pip install lazypredict[viz].
Via LazyForecaster.plot_results()¶
fcst = LazyForecaster(predictions=True, verbose=0)
scores, pred_df = fcst.fit(y_train, y_test)
# Overlay all model forecasts on actual series
fig = fcst.plot_results(plot_type="forecast")
# Bar chart ranking models by a metric
fig = fcst.plot_results(plot_type="comparison", metric="MAE", top_k=10)
# Residual diagnostics (ACF, histogram, Q-Q)
fig = fcst.plot_results(plot_type="residuals", model_name="Ridge_TS")
# Violin plot of absolute errors per model
fig = fcst.plot_results(plot_type="errors")
# Heatmap of all metrics × all models
fig = fcst.plot_results(plot_type="heatmap")
Direct Plotting Functions¶
from lazypredict.ts_visualization import (
plot_forecast,
plot_model_comparison,
plot_residuals,
plot_error_distribution,
plot_metrics_heatmap,
)
# Forecast overlay
fig = plot_forecast(y_train, y_test, predictions={"Ridge_TS": y_pred})
# Model comparison bar chart
fig = plot_model_comparison(scores, metric="RMSE", top_k=10)
# Residuals for one model
fig = plot_residuals(y_test, y_pred, model_name="Ridge_TS", seasonal_period=12)
# Error distribution
fig = plot_error_distribution(y_test, predictions_dict)
# Metrics heatmap
fig = plot_metrics_heatmap(scores)
Ensemble Methods¶
Combine predictions from multiple models after benchmarking.
Via LazyForecaster.ensemble()¶
fcst = LazyForecaster(predictions=True, verbose=0)
scores, pred_df = fcst.fit(y_train, y_test)
# Simple average
avg_pred = fcst.ensemble(method="simple_average")
# Inverse-error weighted (lower validation RMSE = higher weight)
weighted_pred = fcst.ensemble(method="weighted_average")
# Stacking (Ridge meta-model)
stacked_pred = fcst.ensemble(method="stacking")
Weights and the stacking meta-model are learned on a validation window held
out from the end of the training series (each model is refitted on the
rest of y_train), never on y_test, so the ensemble can be evaluated on
y_test like any single model.
Changed in 0.4.0
ensemble() no longer needs y_true; passing it emits a FutureWarning.
Earlier versions fitted the stacking model on y_test, which leaked the
test values into the forecast being evaluated.
Direct Ensemble Functions¶
from lazypredict.ensemble import (
ensemble_simple_average,
ensemble_weighted_average,
ensemble_stacking,
)
predictions = {
"Holt": pred_holt,
"Ridge_TS": pred_ridge,
"LSTM_TS": pred_lstm,
}
# Simple average
avg = ensemble_simple_average(predictions)
# Weighted average (lower score = higher weight)
scores_dict = {"Holt": 3.2, "Ridge_TS": 1.8, "LSTM_TS": 2.5}
weighted = ensemble_weighted_average(predictions, scores=scores_dict)
# Stacking: fit the meta-model on the same models' forecasts of a
# validation period (val_predictions vs. y_val), then apply it to the
# forecasts being combined
stacked = ensemble_stacking(val_predictions, y_true=y_val, pred_test=predictions)
Horizon Strategies¶
Control how ML models generate multi-step forecasts.
from lazypredict.TimeSeriesForecasting import LazyForecaster
# Recursive (default): single model, autoregressively predicts one step at a time
fcst = LazyForecaster(horizon_strategy="recursive")
# Direct: one separate model trained per forecast horizon step
# More accurate for longer horizons but slower
fcst = LazyForecaster(horizon_strategy="direct")
# Multi-output: MultiOutputRegressor wrapping a single model
fcst = LazyForecaster(horizon_strategy="multi_output")
Using horizon functions directly:
from lazypredict.horizon import direct_forecast, multi_output_forecast
from sklearn.linear_model import Ridge
# Direct forecasting
y_pred = direct_forecast(
estimator_class=Ridge,
y_train=y_train,
horizon=20,
n_lags=10,
)
# Multi-output forecasting
y_pred = multi_output_forecast(
estimator_class=Ridge,
y_train=y_train,
horizon=20,
n_lags=10,
)
# With exogenous variables, also pass X_exog (training period) and
# X_future (forecast period).
Both raise a ValueError when y_train is too short to train for the
requested horizon.
Time Series Diagnostics¶
Check whether a model's residuals look like white noise.
from lazypredict.ts_diagnostics import residual_diagnostics
report = residual_diagnostics(y_test, y_pred, seasonal_period=12)
# dict with: residuals, mean, std, ljung_box_stat, ljung_box_pvalue,
# jarque_bera_stat, jarque_bera_pvalue, acf_values, is_white_noise, is_normal
# Or for every fitted forecaster at once:
diagnostics_df = fcst.diagnose()
Distributed / PySpark Support¶
Auto-convert PySpark/Dask DataFrames¶
Lazy Predict automatically converts PySpark and Dask DataFrames to pandas
when they are passed to fit():
# PySpark DataFrame — automatically collected to the driver
from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()
sdf = spark.createDataFrame(df)
clf = LazyClassifier(verbose=0, ignore_warnings=True)
models, predictions = clf.fit(sdf_train, sdf_test, y_train, y_test)
You can also convert explicitly:
from lazypredict.distributed import auto_convert_dataframe
pandas_df = auto_convert_dataframe(spark_df, name="X_train")
Register Dask Joblib Backend¶
from lazypredict.distributed import register_dask_backend
register_dask_backend() # returns False if dask.distributed is unavailable
Spark MLlib Integration¶
Benchmark PySpark MLlib models on large distributed datasets.
Installation¶
Usage¶
from pyspark.sql import SparkSession
from lazypredict.spark import LazySparkClassifier, LazySparkRegressor
spark = SparkSession.builder.appName("LazyPredict").getOrCreate()
# Load data as a Spark DataFrame
train_df = spark.read.csv("train.csv", header=True, inferSchema=True)
test_df = spark.read.csv("test.csv", header=True, inferSchema=True)
feature_cols = [c for c in train_df.columns if c != "label"]
clf = LazySparkClassifier(verbose=1, ignore_warnings=True, label_col="label")
scores = clf.fit(train_df, test_df, feature_cols=feature_cols)
print(scores)
Supported Spark MLlib models:
Classifiers: LogisticRegression, RandomForestClassifier, GBTClassifier, DecisionTreeClassifier, LinearSVC, NaiveBayes
Regressors: LinearRegression, RandomForestRegressor, GBTRegressor, DecisionTreeRegressor, GeneralizedLinearRegression
Time Series Tuning¶
Tune hyperparameters of time series forecasting models directly:
from sklearn.linear_model import Ridge
from lazypredict.TimeSeriesForecasting import MLForecaster
from lazypredict.ts_tuning import tune_forecaster_optuna
# Tune a specific forecaster wrapper with expanding-window CV on y_train
best_params, best_score = tune_forecaster_optuna(
"Ridge_TS",
MLForecaster(Ridge, "Ridge_TS"),
y_train,
X_train=None,
seasonal_period=12,
tune_metric="RMSE",
cv=3,
n_trials=50,
timeout=60,
)
print(f"Best params: {best_params}, Best RMSE: {best_score:.4f}")