{ "cells": [ { "cell_type": "markdown", "id": "e0898d6e", "metadata": {}, "source": [ "# Pipeline selection\n", "\n", "In this tutorial, we will learn how to choose a suitable pipeline for \n", "a PPM task. We will compare two approaches for preparing data before \n", "training Gradient Boosting and Random Forest regressors. The first \n", "approach uses more detailed steps, including timestamp features, \n", "one-hot encoding, and resource pool extraction. The second approach is \n", "simpler and relies only on one-hot encoding. We will train each type \n", "of model with each approach to see how they perform.\n", "\n", "Let us first import the necessary libraries and set the random seed for reproducibility." ] }, { "cell_type": "code", "execution_count": 121, "id": "7b3ee855", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "\n", "from sklearn.pipeline import Pipeline\n", "from sklearn.compose import ColumnTransformer\n", "from sklearn.metrics import root_mean_squared_error\n", "from sklearn.preprocessing import StandardScaler, OneHotEncoder\n", "from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor\n", "from xgboost import XGBRegressor\n", "\n", "from skpm.sequence_encoding import Aggregation\n", "from skpm.config import EventLogConfig as elc\n", "from skpm.event_logs import BPI20PrepaidTravelCosts, split\n", "from skpm.feature_extraction.targets import remaining_time\n", "from skpm.feature_extraction import TimestampExtractor, ResourcePoolExtractor\n", "\n", "# Set random state for reproducible results\n", "RANDOM_STATE = 44\n", "np.random.seed(RANDOM_STATE)" ] }, { "cell_type": "markdown", "id": "3943e804", "metadata": {}, "source": [ "Below we load one of the BPI20 event logs, select relevant columns \n", "for this example, extract the remaining time to use as the target, \n", "and split the data into train and test sets.1" ] }, { "cell_type": "code", "execution_count": null, "id": "43ec9313", "metadata": {}, "outputs": [], "source": [ "from skpm.event_logs.bpi import BPI17\n", "\n", "log = BPI17()\n", "\n", "# Select basic columns\n", "df = log.dataframe[[elc.case_id, elc.activity, elc.resource, elc.timestamp]].copy()\n", "df[elc.timestamp] = pd.to_datetime(df[elc.timestamp], utc=True)\n", "\n", "# Compute remaining time in seconds\n", "df[\"remaining_time\"] = remaining_time(df, time_unit=\"h\")\n", "\n", "# Split into train/test sets using provided split method\n", "train, test = split.unbiased(df, **log.unbiased_split_params)\n", "\n", "# Separate features and targets for train and test\n", "X_train = train.drop(columns=[\"remaining_time\"])\n", "y_train = train[[\"remaining_time\"]]\n", "X_test = test.drop(columns=[\"remaining_time\"])\n", "y_test = test[[\"remaining_time\"]]\n", "\n", "sc = StandardScaler()\n", "y_train = sc.fit_transform(y_train).values.ravel()\n", "y_test = sc.transform(y_test).values.ravel()" ] }, { "cell_type": "markdown", "id": "a4a225d4", "metadata": {}, "source": [ "## Preprocessing pipelines\n", "\n", "We will define two different pipelines for preprocessing the data before\n", "training the models.\n", "\n", "- A **simple** data preparation pipeline: let's just one-hot encode activity labels and discard other features\n", "- A more **complex** one: let's engineer some features from the resources and timestamps. " ] }, { "cell_type": "code", "execution_count": 156, "id": "f337db3c", "metadata": {}, "outputs": [], "source": [ "EVENT_FEATURES = [\n", " \"day_of_month\",\n", " \"day_of_week\",\n", " \"day_of_year\",\n", " \"secs_within_day\",\n", " \"week_of_year\",\n", "]\n", "\n", "data_prep_advanced = Pipeline([\n", " (\"preprocessing\", ColumnTransformer(\n", " transformers=[\n", " (\"timestamp_features\", TimestampExtractor(case_features=\"accumulated_time\", event_features=EVENT_FEATURES), [elc.timestamp, elc.case_id]),\n", " (\"activity_encoder\", OneHotEncoder(sparse_output=False, handle_unknown=\"ignore\"), [elc.activity]),\n", " (\"resource_pool\", ResourcePoolExtractor(threshold=0.5), [elc.case_id, elc.activity, elc.resource]),\n", " (\"case_id_pass\", \"passthrough\", [elc.case_id]),\n", " ])),\n", " (\"encode_agg\", Aggregation(method=\"norm\", prefix_len=3)),\n", " (\"scaling\", StandardScaler()),\n", "])\n", "\n", "data_prep_simple = Pipeline([\n", " (\"preprocessing\", ColumnTransformer(\n", " transformers=[\n", " (\"activity_encoder\", OneHotEncoder(sparse_output=False, handle_unknown=\"ignore\"), [elc.activity]),\n", " (\"case_id_pass\", \"passthrough\", [elc.case_id]),\n", " ])),\n", " (\"encode_agg\", Aggregation(method=\"norm\", prefix_len=3)),\n", " (\"scaling\", StandardScaler()),\n", "])" ] }, { "cell_type": "markdown", "id": "90df3b2f", "metadata": {}, "source": [ "## Training models\n", "\n", "We will train two Gradient Boosting and two Random Forest models\n", "using the advanced and simple preprocessing pipelines. We will then\n", "evaluate the models using the root mean squared error (RMSE) metric." ] }, { "cell_type": "code", "execution_count": 157, "id": "cac5b424", "metadata": {}, "outputs": [], "source": [ "# Gradient Boosting pipelines\n", "gb_pipe_advanced = Pipeline([\n", " (\"preprocessing\", data_prep_advanced),\n", " (\"regressor\", GradientBoostingRegressor(learning_rate=0.2, random_state=RANDOM_STATE))\n", "])\n", "\n", "gb_pipe_simple = Pipeline([\n", " (\"preprocessing\", data_prep_simple),\n", " (\"regressor\", GradientBoostingRegressor(learning_rate=0.2, random_state=RANDOM_STATE))\n", "])\n", "\n", "# Random Forest pipelines\n", "rf_pipe_advanced = Pipeline([\n", " (\"preprocessing\", data_prep_advanced),\n", " (\"regressor\", RandomForestRegressor(max_depth=8, random_state=RANDOM_STATE))\n", "])\n", "\n", "rf_pipe_simple = Pipeline([\n", " (\"preprocessing\", data_prep_simple),\n", " (\"regressor\", RandomForestRegressor(max_depth=8, random_state=RANDOM_STATE))\n", "])\n", "\n", "# Xgb pipelines\n", "xgb_pipe_advanced = Pipeline([\n", " (\"preprocessing\", data_prep_advanced),\n", " (\"regressor\", XGBRegressor(learning_rate=0.2, random_state=RANDOM_STATE))\n", "])\n", "\n", "xgb_pipe_simple = Pipeline([\n", " (\"preprocessing\", data_prep_simple),\n", " (\"regressor\", XGBRegressor(learning_rate=0.2, random_state=RANDOM_STATE))\n", "])" ] }, { "cell_type": "markdown", "id": "225ad6f2", "metadata": {}, "source": [ "Fitting everyone:" ] }, { "cell_type": "code", "execution_count": 158, "id": "048169e4", "metadata": {}, "outputs": [], "source": [ "gb_pipe_advanced.fit(X_train, y_train)\n", "gb_pipe_simple.fit(X_train, y_train)\n", "rf_pipe_advanced.fit(X_train, y_train)\n", "rf_pipe_simple.fit(X_train, y_train)\n", "xgb_pipe_advanced.fit(X_train, y_train)\n", "xgb_pipe_simple.fit(X_train, y_train);" ] }, { "cell_type": "markdown", "id": "0deaf3a7", "metadata": {}, "source": [ "## Results" ] }, { "cell_type": "code", "execution_count": null, "id": "f8ba3b60", "metadata": {}, "outputs": [], "source": [ "scores = pd.DataFrame({\n", " \"model\": [\"GB1_complex\", \"GB2_simple\", \"RF_complex\", \"RF2_simple\", \"XGB_complex\", \"XGB_simple\"],\n", " \"score\": [\n", " root_mean_squared_error(y_test, gb_pipe_advanced.predict(X_test)),\n", " root_mean_squared_error(y_test, gb_pipe_simple.predict(X_test)),\n", " root_mean_squared_error(y_test, rf_pipe_advanced.predict(X_test)),\n", " root_mean_squared_error(y_test, rf_pipe_simple.predict(X_test)),\n", " root_mean_squared_error(y_test, xgb_pipe_advanced.predict(X_test)),\n", " root_mean_squared_error(y_test, xgb_pipe_simple.predict(X_test)),\n", " ]\n", "})" ] }, { "cell_type": "code", "execution_count": 162, "id": "6d2ca484", "metadata": {}, "outputs": [ { "data": { "image/png": "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rSMxMVF79+7VuHHjFB4eLkmqWbOmdfs333yjGjVqaODAgTKZTKpVq5YuX76szz//XL169bJ+YK9du7Z69uwpSYqMjFRsbKy8vLz05JNPSpJ69eqlzZs36+zZs2rYsKH1+C+88IL1vKNGjdKwYcO0b98+PfroowVqXbVqlbp3764OHTpY63zxxRf1+eef64UXXpCTk5NGjx6td955R59//rk2btyoYcOGyc/Pr8jrN5vNMpvN1mWTySR3d/fbft8AAABQvtzqj/NlSbGDhSRt27ZNbm5uSklJUVpamgICAops27FjR7Vo0UInT57UjBkzbIZDubu7Kzo6WpKUnZ2tn376SfPmzZOnp6datGhxyxoSEhLk5OSkxo0bF7r9woULatiwoU1HhIWFKSsrS+np6dYP7b8dvuTk5CQvLy+bddWrV5ckZWZm2hz/tyHD09NTwcHBunDhQpG1xsXFWe9QSDfu0JjNZmVnZ8vNzU01a9ZU3759NXfuXD366KNq27btLa8/JiZGq1atsi7XrVvX+r0EAABAxREUFOToEu5IsYPFiRMntGHDBr3//vtas2aN5syZo/Hjx8tkMikwMFBxcXHKzc2Vi8uNQ1erVk3VqlVTWlpagWPd3Oem2rVr69ChQ/r6669vGyyqVKlS3NILdbPO39b02zsuN4NJfn5+ic+RlZWlqKioQp925erqav33sWPH5OTkpNTUVOXl5dnU8XuRkZHq2rVrgToBAABQsSQlJTns3C4uLvL397+jtsUawJ+dna3Zs2frqaee0gMPPKBhw4bp1KlT+vbbbyVJbdu2VVZWljZv3lz8qm8W5OSknJyc27YLDQ2VxWLRsWPHCt1eq1YtxcfH29whOXHihNzd3eXr61vi+m6Kj4+3/vvKlStKSkpSrVq1Cm1br149JSYmKjAwsMDXzSFZe/bs0b59+zRhwgRdunSpwFyQ33N1dZWHh4f1i2FQAAAAFZPFYnHYV3EUK1gsX75cFotFL7/8siQpICBAffv21bJly5SSkqKGDRuqa9euWrJkif7+978rLi5Oqampio+P19atW2UymWz+sm6xWJSRkaGMjAylpKRoy5YtOnTokB555JHb1hIQEKD27dvrb3/7m/bt26eUlBQdPXpUe/bskSR17txZaWlpWrhwoS5cuKAff/xRK1eu1LPPPntXJkSvXr1aP/30k86d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8+YKDAyUJIWEhNxyH09PT7366qtycnJScHCw1q5dq5ycHOudk8jISMXGxiouLk6PPfaYdb/OnTurdevWkqTBgwfr0KFD2rp1q55//vkC54iNjVW7du307LPPSpKCgoL06quv6n//9381aNAgValSxaZ9TEyMVq1aZV2uW7euoqOjb3v9AAAAKH1BQUGOLsHu7Dp5+/cmT54si8Wiv/71r8rNzbWuf+6559ShQwdZLBalpaXpiy++0EcffaSJEyfKycn2QVZHjhzR3/72Nw0dOlT33nvvbc/p6empDh066MMPP9SDDz6o8PBwtWnTRvfcc0+R+4SEhNict3r16jbncnJykpeXl3755Reb/Ro2bGj9t7Ozs+rVq6cLFy4Ueo6zZ8/q7Nmz2rlzp816i8WilJSUAuEnMjJSXbt2tS5XxlQMAABQViUlJTm6hLvCxcVF/v7+d9a2lGuRJAUGBspkMikxMdFmfc2aNSWpwF/jvby8rHcTgoKC1L9/f40bN05HjhxReHi4td2xY8cUHR2t/v37q3379ndcz4gRIxQREaF///vf2rNnj1asWKFx48bZBIHfcnZ2tlk2mUxycXEpsO6380SKKysrS08++aS6dOlSYJufn1+Bda6urnJ1dS3x+QAAAFB6jHwuLK/s8h4LLy8vhYeHa9OmTcrKyir2/jfvFtwcNiXdmPcwZcoUvfzyy3ryySeLfcy6desqMjJSkyZN0r333qtdu3YV+xi3c/LkSeu/8/LydObMmSLngdStW1cXLlxQYGBgga/fhxgAAACgrLHbC/IGDhyovLw8jR07Vnv27NH58+eVmJio7777ThcuXLAZanT9+nVlZGTo8uXLOnXqlJYtWyZvb2+FhYVJujH86aOPPlJERIRat26tjIwMZWRk6MqVK7etIyUlRcuXL1d8fLxSU1N16NAhJScn33aeRUl888032rdvny5cuKAFCxbo6tWr1idH/d7zzz+vEydOaMGCBUpISFBSUpJ+/PFHLViw4K7XBQAAANxtdvtTeGBgoKZOnaqYmBgtX75caWlpcnV1VUhIiLp166bOnTtb265cuVIrV66UJHl7e+u+++7TuHHjrE9T2rFjh7KzsxUbG6vY2Fjrfo0bN9aECRNuWUeVKlV04cIF7dixQ7/++qvuuecede7cuUR3PW6nT58+io2NVUJCggIDA/XOO+/I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htAnZQ99UvbQJ2UPfVL20CcFESwqkN27d4sbUGWLxWLRzz//TL+UIfRJ2UOflD30SdlDn5Q99ElBBAsAAAAAhhEsAAAAABhGsKggXF1d1atXLyZwlzH0S9lDn5Q99EnZQ5+UPfRJ2UOfFMRToQAAAAAYxh0LAAAAAIYRLAAAAAAYRrAAAAAAYFjFfgd5BbNp0yatW7dOGRkZql27tl577TXVr1+/yPZ79+7Vl19+qdTUVAUGBurll1/Www8/bMeKK4fi9MuWLVv03Xff6T//+Y8kqV69eurdu/ct+xHFV9yflZt2796t6dOnq0WLFnrnnXfsUGnlUdw+uXr1qr744gvt27dPV65ckb+/v/r378//w+6i4vbJhg0btHnzZl26dEne3t5q1aqV+vTpoypVqtix6orr2LFjWrt2rX7++WddvnxZb7/9tlq2bHnLfY4ePaolS5boP//5j2rUqKGePXuqQ4cO9im4Eihun/zwww/avHmzEhISlJubq5CQEL3wwgtq2rSp/Yp2MO5YlBN79uzRkiVL1KtXL0VHR6t27dr68MMP9csvvxTa/sSJE5o+fbqeeOIJRUdH65FHHtG0adN07tw5O1desRW3X44dO6bHHntM//u//6tJkyapRo0amjRpktLT0+1cecVV3D65KSUlRUuXLlWjRo3sVGnlUdw+yc3N1aRJk5Samqo333xTf/nLXzR06FD5+vraufKKq7h9smvXLi1fvlwvvPCCPv30Uw0bNkx79+7VF198YefKK67s7GzVqVNHAwcOvKP2KSkp+uijj9SkSRNNnTpVzz77rObMmaN///vfpVtoJVLcPjl+/LjCw8M1duxYa99ER0fr559/LuVKyw6CRTmxfv16derUSR07dlRISIgGDx6sKlWqaNu2bYW2/8c//qGmTZvqueeeU0hIiF566SXVq1dPmzZtsnPlFVtx++X1119X586dVadOHdWqVUvDhg2TxWLRTz/9ZOfKK67i9okk5efna8aMGYqKilJAQIAdq60citsnW7du1ZUrVzRmzBjdf//9CggIUOPGjVWnTh37Fl6BFbdPTpw4obCwMLVt21YBAQF66KGH9Nhjj+nUqVN2rrziatasmV566aXb3qW4afPmzQoICFC/fv0UEhKiZ555Rq1bt9aGDRtKudLKo7h9MmDAAD3//POqX7++goKC1KdPHwUF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+5WTk6M2bdoUaH/x4kXde++9BUKFJFWvXv0uVg0AFRfBAgBQLqWkpEhSoWGgbdu2unz5so4dO2Zdt2vXLj3wwAOFBgV/f3+dOXNG586du6Nz5+XlKTMzs8BXTk5OCa8GAMo/hkIBAMqFa9euKTMz0zrHYtWqVXJ1dVXz5s0LtA0KCtJ9991nDRNXr17VwYMHNXTo0EKP3a1bN02ePFnvvPOO6tevr/vvv18PPvigmjRpIheXgr8qDx06pEGDBhVY36dPH3Xv3t3wtQJAeUSwAACUCx988IHNsr+/v0aPHq0aNWoU2v6xxx7T6tWrNWjQIH3//fdycnJSy5YtdebMmQJtw8PDNWnSJMXGxurQoUOKj4/X2rVr5e3trWHDhqlFixY27Rs0aKAXX3yxwHGCgoIMXCEAlG8ECwBAuTBw4EAFBQXp2rVr2rZtm44fPy5XV9ci2z/22GNaunSpDh48qF27dunhhx+Wu7t7ke3r16+vt99+W7m5uUpISNC+ffu0YcMG/fnPf9a0adMUEhJibevl5aXw8PC7en0AUN4xxwIAUC7Ur19f4eHhat26td59913de++9mj59urKysgptf88996hJkyZav369jh07prZt297ReVxcXFS/fn316dNHgwcPVl5envbu3Xs3LwUAKiSCBQCg3HFyclKfPn10+fJlbdq0qch2bdu21fHjx+Xh4aGHH3642OepV6+eJOny5cslrhUAKguGQgEAyqUmTZqofv362rBhg7p06WLzkrybWrdurUuXLik4OLjQSdg3HTlyRE2aNJHJZLJZf/DgQUlScHDw3S0eACogggUAoNx67rnn9Mknn2j79u16+umnC2z38PBQVFTUbY+zaNEiZWdnq2XLlgoODlZubq7i4+O1Z88e+fv7q2PHjjbt09PT9d133xU4TtWqVdWyZcuSXxAAlGMECwBAudWyZUvVrFlT69at05NPPlni4/Tt21d79+7VwYMHtWXLFuXm5srPz09PP/20evbsWeBdGQkJCZo5c2aB4/j7+xMsAFRaJovFYnF0EQAAAADKNyZvAwAAADCMYAEAAADAMIIFAAAAAMMIFgAAAAAMI1gAAAAAMIxgAQAAAMAwggUAAAAAwwgWAAAAAAwjWAAAAAAwjGABAAAAwDCCBQAAAADDCBYAAAAADCNYAAAAADDs/wEWdJu7lm2n5AAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "plt.style.use(\"ggplot\")\n", "\n", "scores.plot(\n", " kind=\"barh\", \n", " x=\"model\", \n", " y=\"score\", \n", " color=\"steelblue\", \n", " legend=False,\n", " figsize=(8, 4)\n", ")\n", "plt.ylabel(\"\")\n", "plt.xlabel(\"RMSE\")\n", "# plt.xscale(\"log\")\n", "plt.tight_layout()" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.0" } }, "nbformat": 4, "nbformat_minor": 5 }