Persisted scikit-learn models let trained estimators move from an interactive notebook or training script into a repeatable scoring step. joblib fits trusted Python reuse when the saved object should come back as the original fitted estimator instead of a neutral interchange format.
joblib.dump() stores Python objects through a pickle-based format with efficient handling for large NumPy arrays. Save the fitted object that owns the full prediction path, usually a Pipeline, so preprocessing and estimator parameters stay together.
Only load .joblib artifacts from trusted storage. joblib.load() can execute code through the pickle protocol, and scikit-learn does not support loading models across different scikit-learn versions even when a mismatched artifact appears to load.
from pathlib import Path import joblib import sklearn from joblib import __version__ as joblib_version from sklearn.datasets import load_iris from sklearn.linear_model import LogisticRegression from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler artifact = Path("iris-classifier.joblib") iris = load_iris() model = make_pipeline( StandardScaler(), LogisticRegression(max_iter=200), ) model.fit(iris.data, iris.target) sample = iris.data[[0]] trained_prediction = model.predict(sample) joblib.dump(model, artifact) loaded_model = joblib.load(artifact) loaded_prediction = loaded_model.predict(sample) print(f"saved_artifact: {artifact}") print(f"artifact_exists: {artifact.exists()}") print(f"trained_prediction: {iris.target_names[trained_prediction[0]]}") print(f"loaded_prediction: {iris.target_names[loaded_prediction[0]]}") print(f"prediction_match: {bool((trained_prediction == loaded_prediction).all())}") print(f"sklearn_version: {sklearn.__version__}") print(f"joblib_version: {joblib_version}")
The fitted Pipeline keeps StandardScaler and LogisticRegression together, so the loaded object receives raw feature rows in the same shape as the training code.
$ python persist_model_joblib.py saved_artifact: iris-classifier.joblib artifact_exists: True trained_prediction: setosa loaded_prediction: setosa prediction_match: True sklearn_version: 1.9.0 joblib_version: 1.5.3
Never point joblib.load() at an artifact from an untrusted source. Use skops.io when the file needs type inspection before loading, or ONNX when the scoring environment should not load a Python object.
artifact_exists: True prediction_match: True
artifact_exists confirms that joblib.dump() wrote the artifact, and prediction_match confirms that the reloaded estimator predicts the same class for the sample row.
Use matching Python, scikit-learn, NumPy, SciPy, and joblib versions for training and scoring. Store those versions beside the artifact in project metadata, a lock file, or the deployment image.
$ rm persist_model_joblib.py iris-classifier.joblib