.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/applications/plot_time_series_lagged_features.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. or to run this example in your browser via JupyterLite or Binder .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_applications_plot_time_series_lagged_features.py: =========================================== الميزات المتأخرة للتنبؤ بالسلاسل الزمنية =========================================== هذا المثال يوضح كيفية استخدام الميزات المتأخرة التي تم تصميمها بواسطة Polars في التنبؤ بالسلاسل الزمنية باستخدام :class:`~sklearn.ensemble.HistGradientBoostingRegressor` على مجموعة بيانات طلب مشاركة الدراجات. راجع المثال على :ref:`sphx_glr_auto_examples_applications_plot_cyclical_feature_engineering.py` لاستكشاف بعض البيانات حول هذه المجموعة والاطلاع على عرض توضيحي حول الهندسة الميزات الدورية. .. GENERATED FROM PYTHON SOURCE LINES 12-15 .. code-block:: Python # المؤلفون: مطوري scikit-learn # معرف SPDX-License: BSD-3-Clause .. GENERATED FROM PYTHON SOURCE LINES 16-29 تحليل مجموعة بيانات طلب مشاركة الدراجات ----------------------------------------- نبدأ بتحميل البيانات من مستودع OpenML كملف Parquet خام لتوضيح كيفية العمل مع ملف Parquet عشوائي بدلاً من إخفاء هذه الخطوة في أداة ملائمة مثل `sklearn.datasets.fetch_openml`. يمكن العثور على عنوان URL لملف Parquet في الوصف JSON لمجموعة بيانات طلب مشاركة الدراجات مع معرف 44063 على openml.org (https://openml.org/search?type=data&status=active&id=44063). يتم توفير هاش `sha256` للملف أيضًا لضمان سلامة الملف الذي تم تنزيله. .. GENERATED FROM PYTHON SOURCE LINES 29-57 .. code-block:: Python from sklearn.model_selection import cross_validate from sklearn.metrics import ( make_scorer, mean_absolute_error, mean_pinball_loss, root_mean_squared_error, ) from collections import defaultdict from sklearn.model_selection import cross_val_score from sklearn.model_selection import TimeSeriesSplit from sklearn.metrics import mean_absolute_percentage_error from sklearn.model_selection import train_test_split from sklearn.ensemble import HistGradientBoostingRegressor import matplotlib.pyplot as plt import polars.selectors as cs import numpy as np import polars as pl from sklearn.datasets import fetch_file pl.Config.set_fmt_str_lengths(20) bike_sharing_data_file = fetch_file( "https://openml1.win.tue.nl/datasets/0004/44063/dataset_44063.pq", sha256="d120af76829af0d256338dc6dd4be5df4fd1f35bf3a283cab66a51c1c6abd06a", ) bike_sharing_data_file .. rst-class:: sphx-glr-script-out .. code-block:: none PosixPath('/root/scikit_learn_data/openml1.win.tue.nl/datasets_0004_44063/dataset_44063.pq') .. GENERATED FROM PYTHON SOURCE LINES 58-62 نقوم بتحميل ملف Parquet باستخدام Polars للهندسة الميزات. يقوم Polars تلقائيًا بتخزين التعبيرات الفرعية الشائعة التي يتم إعادة استخدامها في تعبيرات متعددة (مثل `pl.col("count").shift(1)` أدناه). راجع https://docs.pola.rs/user-guide/lazy/optimizations/ لمزيد من المعلومات. .. GENERATED FROM PYTHON SOURCE LINES 62-65 .. code-block:: Python df = pl.read_parquet(bike_sharing_data_file) .. GENERATED FROM PYTHON SOURCE LINES 66-68 بعد ذلك، نلقي نظرة على الملخص الإحصائي لمجموعة البيانات حتى نتمكن من فهم البيانات التي نعمل عليها بشكل أفضل. .. GENERATED FROM PYTHON SOURCE LINES 68-73 .. code-block:: Python summary = df.select(cs.numeric()).describe() summary .. raw:: html
shape: (9, 8)
statisticmonthhourtempfeel_temphumiditywindspeedcount
strf64f64f64f64f64f64f64
"count"17379.017379.017379.017379.017379.017379.017379.0
"null_count"0.00.00.00.00.00.00.0
"mean"6.53777511.54675220.37647423.7887550.62722912.73654189.463088
"std"3.4387766.9144057.8948018.5925110.192938.196795181.387599
"min"1.00.00.820.00.00.01.0
"25%"4.06.013.9416.6650.487.001540.0
"50%"7.012.020.524.240.6312.998142.0
"75%"10.018.027.0631.060.7816.9979281.0
"max"12.023.041.050.01.056.9969977.0


.. GENERATED FROM PYTHON SOURCE LINES 74-76 دعنا نلقي نظرة على عدد المواسم `"fall"`، `"spring"`، `"summer"` و `"winter"` الموجودة في مجموعة البيانات للتأكد من أنها متوازنة. .. GENERATED FROM PYTHON SOURCE LINES 76-81 .. code-block:: Python df["season"].value_counts() .. raw:: html
shape: (4, 2)
seasoncount
catu32
"1"4242
"0"4496
"2"4409
"3"4232


.. GENERATED FROM PYTHON SOURCE LINES 82-89 توليد الميزات المتأخرة المصممة بواسطة Polars -------------------------------------------- دعنا نأخذ في الاعتبار مشكلة التنبؤ بالطلب في الساعة التالية بناءً على الطلبات السابقة. نظرًا لأن الطلب هو متغير مستمر، يمكن للمرء أن يستخدم بشكل حدسي أي نموذج انحدار. ومع ذلك، لا نملك مجموعة البيانات المعتادة `(X_train, y_train)`. بدلاً من ذلك، لدينا فقط بيانات الطلب `y_train` منظمة تسلسليًا حسب الوقت. .. GENERATED FROM PYTHON SOURCE LINES 89-105 .. code-block:: Python lagged_df = df.select( "count", *[pl.col("count").shift(i).alias(f"lagged_count_{i}h") for i in [1, 2, 3]], lagged_count_1d=pl.col("count").shift(24), lagged_count_1d_1h=pl.col("count").shift(24 + 1), lagged_count_7d=pl.col("count").shift(7 * 24), lagged_count_7d_1h=pl.col("count").shift(7 * 24 + 1), lagged_mean_24h=pl.col("count").shift(1).rolling_mean(24), lagged_max_24h=pl.col("count").shift(1).rolling_max(24), lagged_min_24h=pl.col("count").shift(1).rolling_min(24), lagged_mean_7d=pl.col("count").shift(1).rolling_mean(7 * 24), lagged_max_7d=pl.col("count").shift(1).rolling_max(7 * 24), lagged_min_7d=pl.col("count").shift(1).rolling_min(7 * 24), ) lagged_df.tail(10) .. raw:: html
shape: (10, 14)
countlagged_count_1hlagged_count_2hlagged_count_3hlagged_count_1dlagged_count_1d_1hlagged_count_7dlagged_count_7d_1hlagged_mean_24hlagged_max_24hlagged_min_24hlagged_mean_7dlagged_max_7dlagged_min_7d
i64i64i64i64i64i64i64i64f64i64i64f64i64i64
2472032241571601697013593.5224167.7321432711
315247203224138160467097.125247168.7857142711
2143152472031331383346104.5315170.3869053151
1642143152471231333333107.875315171.4642863151
1221642143151251232633109.583333315172.2440483151
1191221642141021252626109.458333315172.8154763151
89119122164721021826110.166667315173.3690483151
908911912247722318110.875315173.7916673151
61908911936472223112.666667315174.1904763151
4961908949361222113.708333315174.4226193151


.. GENERATED FROM PYTHON SOURCE LINES 106-107 ولكن انتبه، فإن الأسطر الأولى لها قيم غير محددة لأن ماضيها غير معروف. يعتمد هذا على مقدار التأخير الذي استخدمناه: .. GENERATED FROM PYTHON SOURCE LINES 107-109 .. code-block:: Python lagged_df.head(10) .. raw:: html
shape: (10, 14)
countlagged_count_1hlagged_count_2hlagged_count_3hlagged_count_1dlagged_count_1d_1hlagged_count_7dlagged_count_7d_1hlagged_mean_24hlagged_max_24hlagged_min_24hlagged_mean_7dlagged_max_7dlagged_min_7d
i64i64i64i64i64i64i64i64f64i64i64f64i64i64
16nullnullnullnullnullnullnullnullnullnullnullnullnull
4016nullnullnullnullnullnullnullnullnullnullnullnull
324016nullnullnullnullnullnullnullnullnullnullnull
13324016nullnullnullnullnullnullnullnullnullnull
1133240nullnullnullnullnullnullnullnullnullnull
111332nullnullnullnullnullnullnullnullnullnull
21113nullnullnullnullnullnullnullnullnullnull
3211nullnullnullnullnullnullnullnullnullnull
8321nullnullnullnullnullnullnullnullnullnull
14832nullnullnullnullnullnullnullnullnullnull


.. GENERATED FROM PYTHON SOURCE LINES 110-112 يمكننا الآن فصل الميزات المتأخرة في مصفوفة `X` ومتغير الهدف (العددات التي يتعين التنبؤ بها) في مصفوفة من نفس البعد الأول `y`. .. GENERATED FROM PYTHON SOURCE LINES 112-116 .. code-block:: Python lagged_df = lagged_df.drop_nulls() X = lagged_df.drop("count") y = lagged_df["count"] print("X shape: {}\ny shape: {}".format(X.shape, y.shape)) .. rst-class:: sphx-glr-script-out .. code-block:: none X shape: (17210, 13) y shape: (17210,) .. GENERATED FROM PYTHON SOURCE LINES 117-124 تقييم ساذج للتنبؤ بالطلب على الدراجات في الساعة التالية -------------------------------------------------------- دعنا نقسم مجموعتنا المجدولة بشكل عشوائي لتدريب نموذج شجرة الانحدار المعزز (GBRT) وتقييمه باستخدام متوسط خطأ النسبة المئوية (MAPE). إذا كان نموذجنا يهدف إلى التنبؤ (أي التنبؤ ببيانات المستقبل من بيانات الماضي)، فيجب علينا عدم استخدام بيانات التدريب التي تكون لاحقة لبيانات الاختبار. في تعلم الآلة للسلاسل الزمنية لا يصح افتراض "i.i.d" (مستقل ومتطابق التوزيع) لأن نقاط البيانات ليست مستقلة ولها علاقة زمنية. .. GENERATED FROM PYTHON SOURCE LINES 124-131 .. code-block:: Python X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) model = HistGradientBoostingRegressor().fit(X_train, y_train) .. GENERATED FROM PYTHON SOURCE LINES 132-133 إلقاء نظرة على أداء النموذج. .. GENERATED FROM PYTHON SOURCE LINES 133-137 .. code-block:: Python y_pred = model.predict(X_test) mean_absolute_percentage_error(y_test, y_pred) .. rst-class:: sphx-glr-script-out .. code-block:: none 0.3928958540837012 .. GENERATED FROM PYTHON SOURCE LINES 138-144 تقييم التنبؤ الصحيح للساعة التالية --------------------------------------- دعنا نستخدم استراتيجيات تقسيم التقييم الصحيحة التي تأخذ في الاعتبار البنية الزمنية لمجموعة البيانات لتقييم قدرة النموذج على التنبؤ بنقاط البيانات في المستقبل (لتجنب الغش عن طريق قراءة القيم من الميزات المتأخرة في مجموعة التدريب). .. GENERATED FROM PYTHON SOURCE LINES 144-153 .. code-block:: Python ts_cv = TimeSeriesSplit( n_splits=3, # للحفاظ على سرعة الكمبيوتر المحمول بما يكفي على أجهزة الكمبيوتر المحمولة الشائعة gap=48, # فجوة بيانات لمدة يومين بين التدريب والاختبار max_train_size=10000, # الحفاظ على مجموعات التدريب بأحجام قابلة للمقارنة test_size=3000, # للحصول على 2 أو 3 أرقام من الدقة في الدرجات ) all_splits = list(ts_cv.split(X, y)) .. GENERATED FROM PYTHON SOURCE LINES 154-155 تدريب النموذج وتقييم أدائه بناءً على MAPE. .. GENERATED FROM PYTHON SOURCE LINES 155-163 .. code-block:: Python train_idx, test_idx = all_splits[0] X_train, X_test = X[train_idx, :], X[test_idx, :] y_train, y_test = y[train_idx], y[test_idx] model = HistGradientBoostingRegressor().fit(X_train, y_train) y_pred = model.predict(X_test) mean_absolute_percentage_error(y_test, y_pred) .. rst-class:: sphx-glr-script-out .. code-block:: none 0.44300751539296973 .. GENERATED FROM PYTHON SOURCE LINES 164-169 خطأ التعميم المقاس عبر تقسيم الاختبار المدرب العشوائي هو متفائل للغاية. من المرجح أن يكون التعميم عبر تقسيم زمني أكثر تمثيلاً للأداء الحقيقي لنموذج الانحدار. دعنا نقيم هذه التباين في تقييم الخطأ لدينا مع تقسيم الصحيح: .. GENERATED FROM PYTHON SOURCE LINES 169-175 .. code-block:: Python cv_mape_scores = -cross_val_score( model, X, y, cv=ts_cv, scoring="neg_mean_absolute_percentage_error" ) cv_mape_scores .. rst-class:: sphx-glr-script-out .. code-block:: none array([0.44300752, 0.27772182, 0.3697178 ]) .. GENERATED FROM PYTHON SOURCE LINES 176-179 التباين عبر التقسيمات كبير جدًا! في إعداد الحياة الواقعية يُنصح باستخدام المزيد من التقسيمات لتقييم التباين بشكل أفضل. دعنا نبلغ عن متوسط درجات CV وانحرافها المعياري من الآن فصاعدًا. .. GENERATED FROM PYTHON SOURCE LINES 179-181 .. code-block:: Python print(f"CV MAPE: {cv_mape_scores.mean():.3f} ± {cv_mape_scores.std():.3f}") .. rst-class:: sphx-glr-script-out .. code-block:: none CV MAPE: 0.363 ± 0.068 .. GENERATED FROM PYTHON SOURCE LINES 182-184 يمكننا حساب العديد من مجموعات مقاييس التقييم ووظائف الخسارة، والتي يتم الإبلاغ عنها أدناه بقليل. .. GENERATED FROM PYTHON SOURCE LINES 184-225 .. code-block:: Python def consolidate_scores(cv_results, scores, metric): if metric == "MAPE": scores[metric].append(f"{value.mean():.2f} ± {value.std():.2f}") else: scores[metric].append(f"{value.mean():.1f} ± {value.std():.1f}") return scores scoring = { "MAPE": make_scorer(mean_absolute_percentage_error), "RMSE": make_scorer(root_mean_squared_error), "MAE": make_scorer(mean_absolute_error), "pinball_loss_05": make_scorer(mean_pinball_loss, alpha=0.05), "pinball_loss_50": make_scorer(mean_pinball_loss, alpha=0.50), "pinball_loss_95": make_scorer(mean_pinball_loss, alpha=0.95), } loss_functions = ["squared_error", "poisson", "absolute_error"] scores = defaultdict(list) for loss_func in loss_functions: model = HistGradientBoostingRegressor(loss=loss_func) cv_results = cross_validate( model, X, y, cv=ts_cv, scoring=scoring, n_jobs=2, ) time = cv_results["fit_time"] scores["loss"].append(loss_func) scores["fit_time"].append(f"{time.mean():.2f} ± {time.std():.2f} s") for key, value in cv_results.items(): if key.startswith("test_"): metric = key.split("test_")[1] scores = consolidate_scores(cv_results, scores, metric) .. GENERATED FROM PYTHON SOURCE LINES 226-241 نمذجة عدم اليقين التنبؤي عبر الانحدار الكمي ------------------------------------------------------- بدلاً من نمذجة القيمة المتوقعة لتوزيع :math:`Y|X` مثلما تفعل خسائر المربعات الصغرى و Poisson، يمكن للمرء أن يحاول تقدير الكميات لتوزيع الشرطي. :math:`Y|X=x_i` من المتوقع أن تكون متغيرًا عشوائيًا لنقطة بيانات معينة :math:`x_i` لأننا نتوقع أن عدد الإيجارات لا يمكن التنبؤ به بدقة 100% من الميزات. يمكن أن يتأثر بعوامل أخرى لا يتم التقاطها بشكل صحيح بواسطة الميزات المتأخرة الموجودة. على سبيل المثال، ما إذا كان سيمطر في الساعة التالية لا يمكن التنبؤ به بالكامل من بيانات إيجار الدراجات في الساعات السابقة. هذا ما نسميه عدم اليقين العشوائي. يجعل الانحدار الكمي من الممكن إعطاء وصف أدق لهذا التوزيع دون افتراضات قوية حول شكله. .. GENERATED FROM PYTHON SOURCE LINES 241-266 .. code-block:: Python quantile_list = [0.05, 0.5, 0.95] for quantile in quantile_list: model = HistGradientBoostingRegressor(loss="quantile", quantile=quantile) cv_results = cross_validate( model, X, y, cv=ts_cv, scoring=scoring, n_jobs=2, ) time = cv_results["fit_time"] scores["fit_time"].append(f"{time.mean():.2f} ± {time.std():.2f} s") scores["loss"].append(f"quantile {int(quantile*100)}") for key, value in cv_results.items(): if key.startswith("test_"): metric = key.split("test_")[1] scores = consolidate_scores(cv_results, scores, metric) scores_df = pl.DataFrame(scores) scores_df .. raw:: html
shape: (6, 8)
lossfit_timeMAPERMSEMAEpinball_loss_05pinball_loss_50pinball_loss_95
strstrstrstrstrstrstrstr
"squared_error""0.33 ± 0.01 s""0.36 ± 0.07""62.3 ± 3.5""39.1 ± 2.3""17.7 ± 1.3""19.5 ± 1.1""21.4 ± 2.4"
"poisson""0.35 ± 0.01 s""0.32 ± 0.07""64.2 ± 4.0""39.3 ± 2.8""16.7 ± 1.5""19.7 ± 1.4""22.6 ± 3.0"
"absolute_error""0.49 ± 0.03 s""0.32 ± 0.06""64.6 ± 3.8""39.9 ± 3.2""17.1 ± 1.1""19.9 ± 1.6""22.7 ± 3.1"
"quantile 5""0.64 ± 0.02 s""0.41 ± 0.01""145.6 ± 20.9""92.5 ± 16.2""5.9 ± 0.9""46.2 ± 8.1""86.6 ± 15.3"
"quantile 50""0.68 ± 0.01 s""0.32 ± 0.06""64.6 ± 3.8""39.9 ± 3.2""17.1 ± 1.1""19.9 ± 1.6""22.7 ± 3.1"
"quantile 95""0.86 ± 0.10 s""1.07 ± 0.27""99.6 ± 8.7""72.0 ± 6.1""62.9 ± 7.4""36.0 ± 3.1""9.1 ± 1.3"


.. GENERATED FROM PYTHON SOURCE LINES 267-268 دعنا نلقي نظرة على الخسائر التي تقلل من كل مقياس. .. GENERATED FROM PYTHON SOURCE LINES 268-282 .. code-block:: Python def min_arg(col): col_split = pl.col(col).str.split(" ") return pl.arg_sort_by( col_split.list.get(0).cast(pl.Float64), col_split.list.get(2).cast(pl.Float64), ).first() scores_df.select( pl.col("loss").get(min_arg(col_name)).alias(col_name) for col_name in scores_df.columns if col_name != "loss" ) .. raw:: html
shape: (1, 7)
fit_timeMAPERMSEMAEpinball_loss_05pinball_loss_50pinball_loss_95
strstrstrstrstrstrstr
"squared_error""absolute_error""squared_error""squared_error""quantile 5""squared_error""quantile 95"


.. GENERATED FROM PYTHON SOURCE LINES 283-294 حتى إذا كانت توزيعات الدرجات تتداخل بسبب التباين في مجموعة البيانات، فمن الصحيح أن متوسط RMSE أقل عندما `loss="squared_error"`، في حين أن متوسط MAPE أقل عندما `loss="absolute_error"` كما هو متوقع. هذا هو أيضًا الحال بالنسبة لمتوسط Pinball Loss مع الكميات 5 و95. الدرجات المقابلة لخسارة الكمية 50 تتداخل مع الدرجات التي تم الحصول عليها عن طريق تقليل وظائف الخسارة الأخرى، وهو أيضًا الحال بالنسبة لـ MAE. نظرة نوعية على التنبؤات ------------------------------------- يمكننا الآن تصور أداء النموذج فيما يتعلق بالخمسة بالمائة، والوسيط، والـ 95 بالمائة: .. GENERATED FROM PYTHON SOURCE LINES 294-317 .. code-block:: Python all_splits = list(ts_cv.split(X, y)) train_idx, test_idx = all_splits[0] X_train, X_test = X[train_idx, :], X[test_idx, :] y_train, y_test = y[train_idx], y[test_idx] X_train, X_test = X[train_idx, :], X[test_idx, :] y_train, y_test = y[train_idx], y[test_idx] max_iter = 50 gbrt_mean_poisson = HistGradientBoostingRegressor( loss="poisson", max_iter=max_iter) gbrt_mean_poisson.fit(X_train, y_train) mean_predictions = gbrt_mean_poisson.predict(X_test) gbrt_median = HistGradientBoostingRegressor( loss="quantile", quantile=0.5, max_iter=max_iter ) gbrt_median.fit(X_train, y_train) median_predictions = gbrt_median.predict(X_test) gbrt_percentile_5 = HistGradientBoostingRegressor( loss="quantile", quantile=0.05, max_iter=max_iter ) .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 12.648 seconds) .. _sphx_glr_download_auto_examples_applications_plot_time_series_lagged_features.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: binder-badge .. image:: images/binder_badge_logo.svg :target: https://mybinder.org/v2/gh/scikit-learn/scikit-learn/main?urlpath=lab/tree/notebooks/auto_examples/applications/plot_time_series_lagged_features.ipynb :alt: Launch binder :width: 150 px .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../../lite/lab/index.html?path=auto_examples/applications/plot_time_series_lagged_features.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_time_series_lagged_features.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_time_series_lagged_features.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_time_series_lagged_features.zip ` .. include:: plot_time_series_lagged_features.recommendations .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_