.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/pitfalls_and_solutions/plot_skd013_train_test_time_overlap.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_pitfalls_and_solutions_plot_skd013_train_test_time_overlap.py: .. _example_skd013_train_test_time_overlap: SKD013 - Train-test overlap in time series ========================================== This example demonstrates mitigations when check :ref:`SKD013 ` fires on temporal data. The check compares datetime columns in train and test folds and flags overlap when the latest training timestamp is not strictly before the earliest test timestamp. Mitigations from the :ref:`automated_checks` user guide: - use a time-based splitter such as :class:`~sklearn.model_selection.TimeSeriesSplit` or similar. We use the employee salaries dataset ordered by hire date and predict whether salary exceeds the median. The goal is to evaluate on future hires only so test scores reflect forward-looking performance. .. GENERATED FROM PYTHON SOURCE LINES 24-33 Load the employee salaries dataset ================================== Rows are sorted by ``date_first_hired``. We expose hire dates as a pandas ``timestamp`` column because SKD013 requires a datetime dtype. Shuffling before a hold-out split mixes later hires into training; that is the pattern SKD013 is designed to catch. Use full :meth:`~skore.EstimatorReport.checks.summarize` on the trigger; ``fast_mode=True`` on fix cells. .. GENERATED FROM PYTHON SOURCE LINES 33-46 .. code-block:: Python import pandas as pd from skrub.datasets import fetch_employee_salaries dataset = fetch_employee_salaries() df = dataset.X.copy() df["current_annual_salary"] = dataset.y df["timestamp"] = pd.to_datetime(df["date_first_hired"]) df = df.sort_values("timestamp").reset_index(drop=True) y = (df["current_annual_salary"] > df["current_annual_salary"].median()).astype(int) X = df.drop(columns=["current_annual_salary"]) .. GENERATED FROM PYTHON SOURCE LINES 47-49 :class:`~skrub.TableReport` confirms chronological ordering and mixed HR features. .. GENERATED FROM PYTHON SOURCE LINES 49-54 .. code-block:: Python from skrub import TableReport TableReport(X) .. raw:: html

Please enable javascript

The skrub table reports need javascript to display correctly. If you are displaying a report in a Jupyter notebook and you see this message, you may need to re-execute the cell or to trust the notebook (button on the top right or "File > Trust notebook").



.. GENERATED FROM PYTHON SOURCE LINES 55-57 The binary target marks above-median earners, a classification view of the salary column. .. GENERATED FROM PYTHON SOURCE LINES 57-60 .. code-block:: Python TableReport(y.to_frame(name="high_earner")) .. raw:: html

Please enable javascript

The skrub table reports need javascript to display correctly. If you are displaying a report in a Jupyter notebook and you see this message, you may need to re-execute the cell or to trust the notebook (button on the top right or "File > Trust notebook").



.. GENERATED FROM PYTHON SOURCE LINES 61-67 Trigger SKD013 - shuffled train/test split ========================================== :class:`~skore.TrainTestSplit` with ``shuffle=True`` randomizes row order before cutting folds, so future timestamps land in training. Fit a tabular classifier and summarize checks. .. GENERATED FROM PYTHON SOURCE LINES 67-82 .. code-block:: Python from skore import TrainTestSplit, evaluate from skrub import tabular_pipeline splitter_shuffled = TrainTestSplit(random_state=42, shuffle=True) report = evaluate( tabular_pipeline("classifier"), X=X, y=y, pos_label=1, splitter=splitter_shuffled, ) report .. raw:: html
Pipeline(steps=[('tablevectorizer',
                     TableVectorizer(low_cardinality=ToCategorical())),
                    ('histgradientboostingclassifier',
                     HistGradientBoostingClassifier())])
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.

Please enable javascript

The skrub table reports need javascript to display correctly. If you are displaying a report in a Jupyter notebook and you see this message, you may need to re-execute the cell or to trust the notebook (button on the top right or "File > Trust notebook").



.. GENERATED FROM PYTHON SOURCE LINES 83-84 SKD013 should list ``timestamp`` as overlapping between train and test. .. GENERATED FROM PYTHON SOURCE LINES 84-87 .. code-block:: Python report.checks.summarize() .. raw:: html


.. GENERATED FROM PYTHON SOURCE LINES 88-90 .. code-block:: Python report.metrics.summarize(data_source="both").frame(favorability=True) .. raw:: html
HistGradientBoostingClassifier (train) HistGradientBoostingClassifier (test) favorability
metric
accuracy 0.986724 0.938787 (↗︎)
precision 0.989136 0.940529 (↗︎)
recall 0.984324 0.935378 (↗︎)
roc_auc 0.999248 0.987546 (↗︎)
log_loss 0.054044 0.144964 (↘︎)
brier_score 0.012418 0.044099 (↘︎)
fit_time 2.153153 2.153153 (↘︎)
predict_time 0.813124 0.258402 (↘︎)


.. GENERATED FROM PYTHON SOURCE LINES 91-93 Optimistic scores under shuffled splits are a leakage artifact; SKD013 forces you to respect time ordering before trusting metrics. .. GENERATED FROM PYTHON SOURCE LINES 95-100 Chronological hold-out ====================== ``shuffle=False`` keeps the test block as the latest rows in the table. No training row should carry a timestamp on or after the earliest test hire. .. GENERATED FROM PYTHON SOURCE LINES 100-112 .. code-block:: Python splitter_chrono = TrainTestSplit(random_state=42, shuffle=False) report_chrono = evaluate( tabular_pipeline("classifier"), X=X, y=y, pos_label=1, splitter=splitter_chrono, ) report_chrono .. raw:: html
Pipeline(steps=[('tablevectorizer',
                     TableVectorizer(low_cardinality=ToCategorical())),
                    ('histgradientboostingclassifier',
                     HistGradientBoostingClassifier())])
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.

Please enable javascript

The skrub table reports need javascript to display correctly. If you are displaying a report in a Jupyter notebook and you see this message, you may need to re-execute the cell or to trust the notebook (button on the top right or "File > Trust notebook").



.. GENERATED FROM PYTHON SOURCE LINES 113-114 SKD013 should be absent; test rows are strictly after train rows. .. GENERATED FROM PYTHON SOURCE LINES 114-117 .. code-block:: Python report_chrono.checks.summarize(fast_mode=True) .. raw:: html


.. GENERATED FROM PYTHON SOURCE LINES 118-120 .. code-block:: Python report_chrono.metrics.summarize(data_source="both").frame(favorability=True) .. raw:: html
HistGradientBoostingClassifier (train) HistGradientBoostingClassifier (test) favorability
metric
accuracy 0.986589 0.924702 (↗︎)
precision 0.988724 0.793956 (↗︎)
recall 0.988028 0.818697 (↗︎)
roc_auc 0.999165 0.974537 (↗︎)
log_loss 0.054945 0.163722 (↘︎)
brier_score 0.012743 0.051262 (↘︎)
fit_time 2.075071 2.075071 (↘︎)
predict_time 0.799283 0.279033 (↘︎)


.. GENERATED FROM PYTHON SOURCE LINES 121-123 A simple chronological hold-out is often enough for deployment monitoring when you score on the most recent period. .. GENERATED FROM PYTHON SOURCE LINES 125-135 TimeSeriesSplit for cross-validated evaluation ============================================== :class:`~sklearn.model_selection.TimeSeriesSplit` trains on past rows and tests on the next chunk in each fold. Many employees share the same hire date, so a default split can still place the same calendar day in train and test at the fold boundary (SKD013 uses ``>=``). A small ``gap`` skips rows between folds and clears that tie. Early folds are small and unrelated checks such as SKD008 may warn on encoded features; we ignore SKD008 here to focus on temporal validity. .. GENERATED FROM PYTHON SOURCE LINES 135-149 .. code-block:: Python from sklearn.model_selection import TimeSeriesSplit splitter_tscv = TimeSeriesSplit(n_splits=5, gap=50) report_tscv = evaluate( tabular_pipeline("classifier"), X=X, y=y, pos_label=1, splitter=splitter_tscv, ) report_tscv .. raw:: html
Pipeline(steps=[('tablevectorizer',
                     TableVectorizer(low_cardinality=ToCategorical())),
                    ('histgradientboostingclassifier',
                     HistGradientBoostingClassifier())])
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.

Please enable javascript

The skrub table reports need javascript to display correctly. If you are displaying a report in a Jupyter notebook and you see this message, you may need to re-execute the cell or to trust the notebook (button on the top right or "File > Trust notebook").



.. GENERATED FROM PYTHON SOURCE LINES 150-152 SKD013 should be absent; no fold trains on timestamps on or after its test block. .. GENERATED FROM PYTHON SOURCE LINES 152-155 .. code-block:: Python report_tscv.checks.summarize(fast_mode=True, ignore=["SKD008"]) .. raw:: html


.. GENERATED FROM PYTHON SOURCE LINES 156-158 .. code-block:: Python report_tscv.metrics.summarize(data_source="both").frame(aggregate="mean") .. raw:: html
histgradientboostingclassifier_(train)_mean histgradientboostingclassifier_(test)_mean
metric
accuracy 0.995496 0.904031
precision 0.996858 0.830040
recall 0.995612 0.915221
roc_auc 0.999742 0.945469
log_loss 0.023280 0.337386
brier_score 0.004806 0.080121
fit_time 1.709548 1.709548
predict_time 0.592657 0.261735


.. GENERATED FROM PYTHON SOURCE LINES 159-161 Time-series cross-validation estimates stability across multiple forward windows, the right tool when a single hold-out is too noisy. .. GENERATED FROM PYTHON SOURCE LINES 163-170 Conclusion ========== SKD013 protects against training on the future. In this walkthrough, disabling shuffle and adopting ``TimeSeriesSplit`` aligned evaluation with how salary models are deployed over newly hired employees. Always pair temporal splits with features available at prediction time. .. rst-class:: sphx-glr-timing **Total running time of the script:** (1 minutes 17.681 seconds) .. _sphx_glr_download_auto_examples_pitfalls_and_solutions_plot_skd013_train_test_time_overlap.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_skd013_train_test_time_overlap.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_skd013_train_test_time_overlap.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_skd013_train_test_time_overlap.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_