{ "cells": [ { "attachments": {}, "cell_type": "markdown", "id": "b773bf8e-c420-44e1-80a6-99f75dd12268", "metadata": {}, "source": [ "## Pipelines and Transformers\n", "\n", "This notebook showcases the current version of data processing pipelines in CapyMOA. \n", "\n", "* Includes examples of how preprocessing can be accomplished via pipelines and transformers.\n", "* Transformers transform an instance, e.g., using standardization, normalization, etc.\n", "* Pipelines bundle transformers, drift detectors, and learners (classifiers, regressors, clustering algorithms etc.)\n", "* Some pipelines act as classifiers or regressors\n", "\n", "Please note that this feature is still under development; some functionality might not yet be available or change in future releases.\n", "\n", "\n", "*More information about CapyMOA can be found in* https://www.capymoa.org\n", "\n", "**notebook last updated on 10/06/2024**\n", "\n", "### Main features\n", "\n", "We've redesigned the pipeline API to be more flexible and modular compared to the initial version.\n", "\n", "- The new API is now generic, meaning it can handle all types of data stream algorithms (e.g., classifiers, regressors, data transformations, change detectors, clustering, etc.). The only requirement is that there exists a `PipelineElement` class compatible with the algorithm. This class represents a single step within the pipeline and provides a unified interface for the overall pipeline object (which is of type `BasePipeline`).\n", "- A pipeline can also function as a `PipelineElement`. This allows for the creation of smaller pipelines that can be combined into a larger pipeline. For instance, you could create separate data cleaning, transformation, and prediction pipelines and then integrate them into one comprehensive pipeline.\n", "- Besides the vanilla `BasePipeline`, we currently support `ClassifierPipeline` and `RegressorPipeline`. These classes act as CapyMOA `Classifiers` and `Regressors`, meaning they support `predict` and `train`.\n", "- Adding drift detectors to a pipeline and specifying their behavior and position within the pipeline is flexible and intuitive.\n", "\n", "This notebook explores these various options with examples.\n", "\n", "### PipelineElements and their structure\n", "\n", "We currently support four types of pipeline elements: `ClassifierPipelineElement`, `RegressorPipelineElement`, `TransformerPipelineElement`, and `DriftDetectorPipelineElement`. They all implement the `PipelineElement` protocol, which provides two functions:\n", "\n", "1. `pass_forward(instance) -> Instance`\n", " - Passes the instance through the pipeline.\n", " - The specific action taken depends on the type of pipeline element.\n", " - For example, a `TransformerPipelineElement` applies a transformation to the instance.\n", "2. `pass_forward_predict(instance, prediction) -> Tuple[Instance, Any]`\n", " - Similar to `pass_forward` but can also pass along a prediction.\n", " - For example, a classifier could predict the instance's label and then pass the tuple `(instance, prediction)` to the next element in the pipeline.\n", "\n", "This protocol offers great flexibility. For instance, one could develop a `ClusteringPipelineElement` that performs clustering and then passes the instance and clustering result to the next element in the pipeline.\n", "\n", "Let's now look at the currently supported pipeline elements:\n", "\n", "#### TransformerPipelineElement\n", "This element is initialized with a CapyMOA `Transformer`.\n", "- `pass_forward` transforms and returns the provided instance.\n", "- `pass_forward_predict` transforms the provided instance and returns the transformed instance and the input prediction.\n", "\n", "#### ClassifierPipelineElement and RegressorPipelineElement\n", "These elements are initialized with a CapyMOA `Classifier` or `Regressor`.\n", "- `pass_forward` trains the learner on the provided instance.\n", "- `pass_forward_predict` predicts the label/value of the instance and returns `(instance, prediction)`.\n", "\n", "#### DriftDetectorPipelineElement\n", "This element is initialized with a CapyMOA `BaseDriftDetector` and a callable `prepare_drift_detector_input_func` that takes an instance as input and returns the input for the change detector.\n", "- `pass_forward` does nothing.\n", "- `pass_forward_predict` updates the change detector. Internally, the drift detector calls `prepare_drift_detector_input_func` and passes the output to the change detector.\n", "\n", "The `prepare_drift_detector_input_func` offers flexibility: it can be used to select a subset of features for the drift detector to monitor (e.g., for unsupervised drift detection), to compute the prediction error (e.g., for regression), or to check if the prediction matches the label (for classification).\n", "\n", "#### BasePipeline (and inheritors)\n", "Pipelines themselves are pipeline elements, allowing you to combine them into larger pipelines.\n", "- `pass_forward` calls `pass_forward` on all its elements.\n", "- `pass_forward_predict` calls `pass_forward_predict` on all its elements." ] }, { "attachments": {}, "cell_type": "markdown", "id": "55d070de-8697-4f98-a11b-eab4e3d5c281", "metadata": {}, "source": [ "## 1. Running onlineBagging without any preprocessing\n", "\n", "First, let us have a look at a simple test-then-train classification example without pipelines. \n", "- We loop over the instances of the data stream\n", "- make a prediction,\n", "- update the evaluator with the prediction and label\n", "- and then train the classifier on the instance." ] }, { "cell_type": "code", "execution_count": 1, "id": "49ff5008", "metadata": { "nbsphinx": "hidden" }, "outputs": [], "source": [ "# This cell is hidden on capymoa.org. See docs/contributing/docs.rst\n", "from util.nbmock import mock_datasets, is_nb_fast\n", "\n", "if is_nb_fast():\n", " mock_datasets()" ] }, { "cell_type": "code", "execution_count": 2, "id": "14681f54-23a1-4f93-9145-abf484c91c54", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "82.06656073446328" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "## Test-then-train loop\n", "from capymoa.datasets import Electricity\n", "from capymoa.classifier import OnlineBagging\n", "from capymoa.evaluation import ClassificationEvaluator\n", "\n", "## Opening a file as a stream\n", "elec_stream = Electricity()\n", "\n", "# Creating a learner\n", "ob_learner = OnlineBagging(schema=elec_stream.get_schema(), ensemble_size=5)\n", "\n", "# Creating the evaluator\n", "ob_evaluator = ClassificationEvaluator(schema=elec_stream.get_schema())\n", "\n", "while elec_stream.has_more_instances():\n", " instance = elec_stream.next_instance()\n", "\n", " prediction = ob_learner.predict(instance)\n", " ob_evaluator.update(instance.y_index, prediction)\n", " ob_learner.train(instance)\n", "\n", "ob_evaluator.accuracy()" ] }, { "cell_type": "markdown", "id": "94362841-b267-471b-9a8c-b4094ad81acb", "metadata": {}, "source": [ "## 2. Transforming instances using pipelines\n", "\n", "If we want to perform some preprocessing, such as normalization or feature transformation, or a combination of both, we can chain multiple `Transformer`s within a pipeline. The most basic pipeline class `BasePipeline` already supports this.\n", "\n", "Creating a basic pipeline consists of the following steps:\n", "1. Create a stream instance\n", "2. Initialize the transformers\n", "4. Create the `BasePipeline`\n", "5. Add the transformers to the pipeline\n", "6. Call `pass_forward` to apply the transformations:" ] }, { "cell_type": "code", "execution_count": 3, "id": "6724b905-53a0-49e9-b8a6-af1b30aececc", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "77.5048552259887" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from capymoa.stream.preprocessing import MOATransformer\n", "from capymoa.stream.preprocessing import BasePipeline\n", "from capymoa.stream import Stream\n", "from moa.streams.filters import AddNoiseFilter, NormalisationFilter\n", "from moa.streams import FilteredStream\n", "\n", "elec_stream = Electricity()\n", "\n", "# Creating the transformers\n", "normalisation_transformer = MOATransformer(schema=elec_stream.get_schema(), moa_filter=NormalisationFilter())\n", "add_noise_transformer = MOATransformer(schema=normalisation_transformer.get_schema(), moa_filter=AddNoiseFilter())\n", "\n", "# Creating and populating the pipeline\n", "pipeline = BasePipeline()\n", "\n", "# Add the transformers to the pipeline. We can change the calls to add_transformer, as they return self\n", "pipeline = (pipeline\n", " .add_transformer(normalisation_transformer)\n", " .add_transformer(add_noise_transformer))\n", "\n", "# Creating a learner\n", "ob_learner = OnlineBagging(schema=add_noise_transformer.get_schema(), ensemble_size=5)\n", "\n", "# Creating the evaluator\n", "ob_evaluator = ClassificationEvaluator(schema=elec_stream.get_schema()) \n", "\n", "while elec_stream.has_more_instances():\n", " instance = elec_stream.next_instance()\n", " transformed_instance = pipeline.pass_forward(instance)\n", " prediction = ob_learner.predict(transformed_instance)\n", " ob_evaluator.update(instance.y_index, prediction)\n", " ob_learner.train(transformed_instance)\n", "\n", "ob_evaluator.accuracy()" ] }, { "attachments": {}, "cell_type": "markdown", "id": "0c1360ef-0583-4c87-8645-1e2d701fffca", "metadata": {}, "source": [ "## 2. Online Bagging using pipelines and transformers\n", "\n", "Similar as classifiers, a `ClassifierPipeline` supports `train` and `test`. Hence, we can use it in the same way as we would use other capymoa classifiers. \n", "\n", "- When calling `train`, the pipeline object internally calls `pass_forward` on all elements.\n", "- When calling test, the pipeline object internally calls `pass_forward_predict` on all elements and then returns the resulting prediction.\n", "\n", "Creating a pipeline consists of the following steps:\n", "\n", "1. Create a stream instance\n", "2. Initialize the transformers\n", "3. Initialize the learner\n", "4. Create the pipeline. Here, we use a `ClassifierPipeline`\n", "5. Add the transformers and the classifier\n", "6. Use the pipeline the same way as any other learner." ] }, { "cell_type": "code", "execution_count": 4, "id": "ae9bb646-e0d1-4de6-b5a1-cff0f0a1b172", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "77.5048552259887" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from capymoa.stream.preprocessing import MOATransformer\n", "from capymoa.stream.preprocessing import ClassifierPipeline\n", "from moa.streams.filters import AddNoiseFilter, NormalisationFilter\n", "\n", "elec_stream = Electricity()\n", "\n", "# Creating the transformers\n", "normalisation_transformer = MOATransformer(\n", " schema=elec_stream.get_schema(), moa_filter=NormalisationFilter()\n", ")\n", "add_noise_transformer = MOATransformer(\n", " schema=normalisation_transformer.get_schema(), moa_filter=AddNoiseFilter()\n", ")\n", "\n", "# Creating a learner\n", "ob_learner = OnlineBagging(schema=add_noise_transformer.get_schema(), ensemble_size=5)\n", "\n", "# Creating and populating the pipeline\n", "pipeline = (ClassifierPipeline()\n", " .add_transformer(normalisation_transformer)\n", " .add_transformer(add_noise_transformer)\n", " .add_classifier(ob_learner))\n", "\n", "# Creating the evaluator\n", "ob_evaluator = ClassificationEvaluator(schema=elec_stream.get_schema())\n", "\n", "while elec_stream.has_more_instances():\n", " instance = elec_stream.next_instance()\n", " prediction = pipeline.predict(instance)\n", " ob_evaluator.update(instance.y_index, prediction)\n", " pipeline.train(instance)\n", "\n", "ob_evaluator.accuracy()" ] }, { "cell_type": "markdown", "id": "676f53b7-0839-47a5-88f9-393b2007855e", "metadata": {}, "source": [ "We can also get a textual representation of the pipeline:" ] }, { "cell_type": "code", "execution_count": 5, "id": "31a481db-d23b-4fc8-a689-fc5c14df5fff", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'PE(Transformer(NormalisationFilter)) | PE(Transformer(AddNoiseFilter)) | PE(OnlineBagging) | '" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "str(pipeline)" ] }, { "cell_type": "markdown", "id": "df255274-83cd-41df-a1da-04778bc427aa", "metadata": {}, "source": [ "### 2.1 Alternative syntax\n", "* An alternative syntax to define the pipeline is shown below\n", "* Since the pipeline behaves like a learner, it can be used with high-level evaluation functions like `prequential_evaluation`" ] }, { "cell_type": "code", "execution_count": 6, "id": "50cb066b-e3e4-4ffd-ad9d-65631d5462e3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AdaptiveRandomForest: 88.55049435028248\n", "PE(Transformer(NormalisationFilter)) | PE(AdaptiveRandomForest) | : 88.04069562146893\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA+UAAAHWCAYAAAARsiigAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAADGp0lEQVR4nOzdd3gUZdfH8e+m9wQIJYFAgNB77wiIoCCCdEWKBRVBxIKAiqI+vAqKiviI+KiAiBRBEQUpKr33IlV67xDSy877x5CFJQEhJpmU3+e69srszOzM2dnZzZ697zm3zTAMAxERERERERHJci5WByAiIiIiIiKSVykpFxEREREREbGIknIRERERERERiygpFxEREREREbGIknIRERERERERiygpFxEREREREbGIknIRERERERERiygpFxEREREREbGIknIRERERERERiygpFxEREREREbGIknIRERERERERiygpFxEREREREbGIknIRERFJt+joaKtDEBERydGUlIuIiGQjR44c4bnnnqNcuXJ4e3tToEABunTpwuHDh1Ote/nyZV588UXCw8Px9PSkWLFi9OrVi/PnzzvWiYuLY8SIEZQtWxYvLy9CQkLo2LEjBw4cAGDp0qXYbDaWLl3qtO3Dhw9js9mYNGmSY16fPn3w8/PjwIEDtGnTBn9/f3r06AHAihUr6NKlC8WLF8fT05OwsDBefPFFYmNjU8W9Z88eunbtSsGCBfH29qZcuXK8/vrrACxZsgSbzcZPP/2U6nHff/89NpuNNWvW3O1hFRERybbcrA5ARERErtuwYQOrV6+me/fuFCtWjMOHDzN+/HiaNWvGrl278PHxASAqKoomTZqwe/dunnjiCWrWrMn58+eZO3cux48fJzg4mOTkZB588EH++OMPunfvzgsvvMDVq1dZvHgxO3fupHTp0ncdX1JSEq1bt6Zx48Z8+OGHjnh++OEHYmJi6NevHwUKFGD9+vWMGzeO48eP88MPPzgev337dpo0aYK7uztPP/004eHhHDhwgF9++YWRI0fSrFkzwsLCmDp1Kg8//LDTvqdOnUrp0qVp0KDBvzjCIiIi2YuSchERkWykbdu2dO7c2Wleu3btaNCgAbNnz6Znz54AfPDBB+zcuZMff/zRKXl94403MAwDgG+//ZY//viDjz76iBdffNGxztChQx3r3K34+Hi6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Pz84k509e5bTp0873VIKDjRv3pyoqCinoZjuVkrrxrhx4zh48CBz586963GrY2NjGTBgAEuXLuXIkSOsWrWKDRs2UKFChVs+5uWXX+aPP/7g3XffZd++fUyePJnPPvuMV155Jd3P5VbKli1Ljx496NOnD7/88guHDh1i/fr1vPfee45idrdyp8d42LBhnDx50qkomK+vL/369WPw4MEsWLCAXbt20bdvX2JiYtIcmurfKlOmDBs3bmThwoXs27eP4cOH39W407/++iuffvopW7du5ciRI3z77bfY7XbKlStHvnz5KFCgAF9++SV///03f/75p9MlJmBeZ+7t7c2CBQs4c+aMo7L2jbL6mKQlPDycdevWcfjwYUc3/P79+3Px4kUeeeQRNmzYwIEDB1i4cCGPP/74HSWKK1asoFWrVqnmpVSpzmyGYaT6nDh9+rSjBbF169b89ddfTj+kfP3113Tu3JnKlSs73Z588knOnz/PggULaNmyJWXLlqV3795s27aNFStWOF1TD+Z5d/ToUaZPn86BAwf49NNP+emnn1LF6OXl5bSdgQMH0rVrV8cPY+Hh4Wzfvp29e/dy/vz5WxZWCQ8Pd1RMT05O5qGHHnIsa9myJQ0aNKBDhw4sWrSIw4cPs3r1al5//fVU3ftvFBYWxsMPP+wY4vBOn9Pt+Pn58eSTTzJ48GD+/PNPdu7cSZ8+fZx+VClTpgzt27enb9++rFy5km3btvHYY49RtGjRTP1hO72fv0OGDHEUhdu6dSv79+/n559/ZsCAAcDtP0Mg7fcewOHDhzlx4kSWjtIiIiKS0SxNyq9cuUL//v0pX748vXr1onHjxixcuNDR1D937lxq1KjhGFKqe/fu1KhRw6m7ZHYQHuzLkPvLM+6RGgy5v3ymtpDfjXLlyhESEuJ0S7lev0CBAjz88MNMnTo13dsvWLAgkyZN4ocffqBixYq8//77fPjhh3e1DVdXVy5cuECvXr0oW7YsXbt25YEHHkizWF+KmjVrMnPmTKZPn07lypV58803eeedd5wq/2akiRMn0rNnT9544w0qVKhAhw4d2LBhQ6pCeje702OcP39+hgwZQlxcnNP8999/n06dOtGzZ09q1qzJ33//zcKFCx0V1jPSM888Q8eOHenWrRv16tXjwoULPPfcc3f8+KCgIH788UdatGhBhQoV+OKLL5g2bRqVKlVydI/ftGkTlStX5sUXX+SDDz5werybmxuffvopEyZMIDQ09JZJRVYek7S88soruLq6UrFiRcflGqGhoaxatYrk5GRatWpFlSpVGDRokKPL8+2kVCW/sWAiwPTp0+nbt29mPhWHlEuHbrwVLVqUc+fOAVClShXHew7MOhLbtm2jU6dOqbYVGBjIvffey9dff42Liws//fQTsbGx1K1bl6eeeoqRI0c6rf/QQw/x4osvMmDAAKpXr87q1asd1bpvFBERQceOHWnTpg2tWrWiatWqfP75547lffv2pVy5ctSuXZuCBQumasm9UY8ePdi2bRsPP/yw048eNpuN+fPn07RpUx5//HHKli1L9+7dOXLkiNMQcWl58cUXmTdvHuvXr7/j5/RPPvjgA5o0aUK7du1o2bIljRs3platWk7rTJw4kVq1avHggw/SoEEDDMNg/vz5mdpNL72fv1WrVmXZsmXs27ePJk2aUKNGDd58803Hte23+wyBtN97ANOmTaNVq1aUKFEi056ziIhIZrMZ/6b/cg4QGRlJYGBgmhWG4+LiOHToECVLlsyThVy2b9/Offfdx4EDB5yKFElqKdfYBgQE3FUXYB1juZ1u3bpRrVo1p4Jav/32Gy+//DLbt2+/7aUpkyZNYtKkSWleA/1v3Xy+z5s3j8GDB/9jHYrMMGLECObMmcPWrVuzdL+S/SUkJFCmTBm+//57x4gMt2Kz2Th06FCqIQZv9dme178fSO6UmJjI/PnzadOmja4pl1wvO5zvt8tDb5YtrikXa1StWpVRo0Zx6NAhq0PJtXSM5VYSEhKoUqUKL774otP86OhoJk6cmK5aEZmlbdu2PP3005w4ccLqUEQcjh49ymuvvfaPCbmIiEh2l32+9YklMqvLt1ynYyxp8fDw4I033kg1/+au7NnFoEGDrA5BxElKoTgREZGcTi3lIiI5UPXq1fPEDz4jRoxQ13X51956661bDhEqIiJiNbWUi4jkQNWrV6d69epWhyGSI4wYMcLqEEQkL7pwALZMgctHIag41OgJBUpbHVXOlkuPqZJyERERERGRjLTlO5j7PGADDPPvqrHw0GdQo4fFweVQufiYKikXERERERHJKBcOmMmjYU+9bG5/cPOCgNCsjysnu3IC5g6AtAYOmzsAitfP0S3mSspFREREREQyypYpmK25aTAMmP1E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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from capymoa.evaluation import prequential_evaluation\n", "from capymoa.classifier import AdaptiveRandomForestClassifier\n", "from capymoa.evaluation.visualization import plot_windowed_results\n", "from capymoa.stream.preprocessing import TransformerPipelineElement, ClassifierPipelineElement\n", "\n", "elec_stream = Electricity()\n", "\n", "# Creating a transformer\n", "normalisation_transformer = MOATransformer(\n", " schema=elec_stream.get_schema(), moa_filter=NormalisationFilter()\n", ")\n", "\n", "# Creating an ARF classifier as a baseline\n", "arf = AdaptiveRandomForestClassifier(\n", " schema=normalisation_transformer.get_schema(), ensemble_size=5\n", ")\n", "\n", "# Alternative syntax. \n", "## first create the pipeline elements\n", "normalisation_transformer_pe = TransformerPipelineElement(normalisation_transformer)\n", "classifier_pe = ClassifierPipelineElement(AdaptiveRandomForestClassifier(schema=add_noise_transformer.get_schema(), ensemble_size=5))\n", "## then pass them as a list to the pipeline initializer\n", "pipeline_arf = ClassifierPipeline([normalisation_transformer_pe, classifier_pe])\n", "\n", "results_arf_pipeline = prequential_evaluation(stream=elec_stream, learner=pipeline_arf, window_size=4500)\n", "results_arf_baseline = prequential_evaluation(stream=elec_stream, learner=arf, window_size=4500)\n", "\n", "print(f\"{arf}: {results_arf_baseline['cumulative'].accuracy()}\")\n", "print(f\"{pipeline_arf}: {results_arf_pipeline['cumulative'].accuracy()}\")\n", "plot_windowed_results(results_arf_pipeline, results_arf_baseline, metric=\"accuracy\", figure_path=None)" ] }, { "cell_type": "markdown", "id": "5cc06f0d-d2a0-4fc6-aa9f-ea80e0d224cd", "metadata": {}, "source": [ "## 3. RegressorPipeline\n", "\n", "* The regression version of the pipeline is quite similar to the classification one" ] }, { "cell_type": "code", "execution_count": 7, "id": "f3c8271b-bbb7-4ca9-97f5-fb41e27ec4fd", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2.5841013025710358\n" ] } ], "source": [ "from capymoa.regressor import AdaptiveRandomForestRegressor\n", "from capymoa.stream.preprocessing import RegressorPipeline\n", "from capymoa.evaluation import RegressionEvaluator\n", "from capymoa.datasets import Fried\n", "\n", "fried_stream = Fried()\n", "\n", "# Creating a transformer\n", "normalisation_transformer = MOATransformer(\n", " schema=fried_stream.get_schema(), moa_filter=NormalisationFilter()\n", ")\n", "\n", "arfreg = AdaptiveRandomForestRegressor(\n", " schema=normalisation_transformer.get_schema(), ensemble_size=5\n", ")\n", "\n", "# Creating and populating the pipeline\n", "pipeline_arfreg = RegressorPipeline()\n", "pipeline_arfreg.add_transformer(normalisation_transformer)\n", "pipeline_arfreg.add_regressor(arfreg)\n", "\n", "# Creating the evaluator\n", "arfreg_evaluator = RegressionEvaluator(schema=fried_stream.get_schema())\n", "\n", "while fried_stream.has_more_instances():\n", " instance = fried_stream.next_instance()\n", " prediction = pipeline_arfreg.predict(instance)\n", " arfreg_evaluator.update(instance.y_value, prediction)\n", " pipeline_arfreg.train(instance)\n", "\n", "print(arfreg_evaluator.rmse())" ] }, { "cell_type": "markdown", "id": "cfd6bceb-9969-4b79-8f91-1d312c72c331", "metadata": {}, "source": [ "## 4. Adding a drift detector to the pipeline\n", "\n", "Let us now add a change detector to the pipeline from section 2.\n", "\n", "Adding a drift detector to a pipeline requires the following steps:\n", "1. create the drift detector\n", "2. define a function that prepares the input for the drift detector based on an instance and a prediction (which can be `None`)\n", "3. create and populate the pipeline\n", "4. run the pipeline" ] }, { "cell_type": "markdown", "id": "4ac8bbd3-009d-4af3-b6a4-23e004f1ba6f", "metadata": {}, "source": [ "### 4.1 Monitoring classifier accuracy" ] }, { "cell_type": "code", "execution_count": 8, "id": "5e18f1ad-c358-4773-8904-b33787585021", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Detected change at index 3487\n", "Detected change at index 8735\n", "Detected change at index 10399\n", "Detected change at index 10559\n", "Detected change at index 10751\n", "Detected change at index 11039\n", "Detected change at index 13343\n", "Detected change at index 13855\n", "Detected change at index 17247\n", "Detected change at index 17343\n", "Detected change at index 18623\n", "Detected change at index 18719\n", "Detected change at index 18975\n", "Detected change at index 19295\n", "Detected change at index 21215\n", "Detected change at index 21375\n", "Detected change at index 23359\n", "Detected change at index 23391\n", "Detected change at index 24127\n", "Detected change at index 25023\n", "Detected change at index 25119\n", "Detected change at index 35327\n", "Detected change at index 35487\n", "Detected change at index 39999\n", "Detected change at index 40127\n", "Detected change at index 40991\n", "Detected change at index 41439\n" ] }, { "data": { "text/plain": [ "77.5048552259887" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from capymoa.drift.detectors import ADWIN\n", "from capymoa.instance import LabeledInstance\n", "from capymoa.type_alias import LabelIndex\n", "\n", "elec_stream = Electricity()\n", "\n", "# Creating the transformers\n", "normalisation_transformer = MOATransformer(schema=elec_stream.get_schema(), moa_filter=NormalisationFilter())\n", "add_noise_transformer = MOATransformer(schema=normalisation_transformer.get_schema(), moa_filter=AddNoiseFilter())\n", "\n", "# Creating a learner\n", "ob_learner = OnlineBagging(schema=add_noise_transformer.get_schema(), ensemble_size=5)\n", "\n", "# Creating a drift detector\n", "drift_detector = ADWIN()\n", "\n", "# Define a function that prepares the input of the drift detector\n", "def label_equals_prediction(instance: LabeledInstance, prediction: LabelIndex) -> LabelIndex:\n", " label = instance.y_index\n", " return int(label == prediction)\n", "\n", "# Creating and populating the pipeline\n", "pipeline = (ClassifierPipeline()\n", " .add_transformer(normalisation_transformer)\n", " .add_transformer(add_noise_transformer)\n", " .add_classifier(ob_learner)\n", " .add_drift_detector(drift_detector, get_drift_detector_input_func=label_equals_prediction))\n", "\n", "# Creating the evaluator\n", "ob_evaluator = ClassificationEvaluator(schema=elec_stream.get_schema()) \n", "\n", "i = 0\n", "while elec_stream.has_more_instances():\n", " instance = elec_stream.next_instance()\n", " prediction = pipeline.predict(instance)\n", " ob_evaluator.update(instance.y_index, prediction)\n", " pipeline.train(instance)\n", " if drift_detector.detected_change():\n", " print(f\"Detected change at index {i}\")\n", " i += 1\n", "\n", "ob_evaluator.accuracy()" ] }, { "cell_type": "markdown", "id": "0392072a-79e6-41d2-9a0c-f72358e936b0", "metadata": {}, "source": [ "### 4.2 Monitoring drift in the first input feature\n", "\n", "We now show how one can easily monitor an input feature by adapting `get_drift_detector_input_func` and the position of the drift detector in the pipline. \n", "\n", "For the sake of illustration, this example is very simple. However, one can easily think of more complex use cases of `get_drift_detector_input_func`. One can provide any object that implements `__call__(instance, prediction)`. For example, one could provide a class that monitors the correlation between a set of input features." ] }, { "cell_type": "code", "execution_count": 9, "id": "d6f2794b-9a65-4be1-a678-fa90dff05c5f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Detected change at index 95\n", "Detected change at index 159\n" ] }, { "data": { "text/plain": [ "77.5048552259887" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from capymoa.drift.detectors import ADWIN\n", "from capymoa.instance import LabeledInstance\n", "from capymoa.type_alias import LabelIndex\n", "\n", "elec_stream = Electricity()\n", "\n", "# Creating the transformers\n", "normalisation_transformer = MOATransformer(schema=elec_stream.get_schema(), moa_filter=NormalisationFilter())\n", "add_noise_transformer = MOATransformer(schema=normalisation_transformer.get_schema(), moa_filter=AddNoiseFilter())\n", "\n", "# Creating a learner\n", "ob_learner = OnlineBagging(schema=add_noise_transformer.get_schema(), ensemble_size=5)\n", "\n", "# Creating a drift detector\n", "drift_detector = ADWIN()\n", "\n", "# Define a function that prepares the input of the drift detector\n", "def first_feature_is_gt_zero(instance: LabeledInstance, prediction: LabelIndex) -> LabelIndex:\n", " feature_val = instance.x[0]\n", " return int(feature_val > 0.0)\n", "\n", "# Creating and populating the pipeline\n", "pipeline = (ClassifierPipeline()\n", " .add_transformer(normalisation_transformer)\n", " # here, we add the drift detector after the normalization step\n", " .add_drift_detector(drift_detector, get_drift_detector_input_func=first_feature_is_gt_zero) \n", " .add_transformer(add_noise_transformer)\n", " .add_classifier(ob_learner)\n", " )\n", "\n", "# Creating the evaluator\n", "ob_evaluator = ClassificationEvaluator(schema=elec_stream.get_schema()) \n", "\n", "i = 0\n", "while elec_stream.has_more_instances():\n", " instance = elec_stream.next_instance()\n", " prediction = pipeline.predict(instance)\n", " ob_evaluator.update(instance.y_index, prediction)\n", " pipeline.train(instance)\n", " if drift_detector.detected_change():\n", " print(f\"Detected change at index {i}\")\n", " i += 1\n", "\n", "ob_evaluator.accuracy()" ] }, { "cell_type": "markdown", "id": "770f37d9-c293-4379-9412-a07701fe57f3", "metadata": {}, "source": [ "## 5. Pipelines within pipelines\n", "\n", "The following example is based on section 4.1 and shows how one can plug together multiple pipelines" ] }, { "cell_type": "code", "execution_count": 10, "id": "a4fecd51-b0ed-4cf1-b54e-dd3c4185f537", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Detected change at index 3487\n", "Detected change at index 8735\n", "Detected change at index 10399\n", "Detected change at index 10559\n", "Detected change at index 10751\n", "Detected change at index 11039\n", "Detected change at index 13343\n", "Detected change at index 13855\n", "Detected change at index 17247\n", "Detected change at index 17343\n", "Detected change at index 18623\n", "Detected change at index 18719\n", "Detected change at index 18975\n", "Detected change at index 19295\n", "Detected change at index 21215\n", "Detected change at index 21375\n", "Detected change at index 23359\n", "Detected change at index 23391\n", "Detected change at index 24127\n", "Detected change at index 25023\n", "Detected change at index 25119\n", "Detected change at index 35327\n", "Detected change at index 35487\n", "Detected change at index 39999\n", "Detected change at index 40127\n", "Detected change at index 40991\n", "Detected change at index 41439\n" ] }, { "data": { "text/plain": [ "77.5048552259887" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from capymoa.drift.detectors import ADWIN\n", "from capymoa.instance import LabeledInstance\n", "from capymoa.type_alias import LabelIndex\n", "\n", "elec_stream = Electricity()\n", "\n", "# Creating the transformers\n", "normalisation_transformer = MOATransformer(schema=elec_stream.get_schema(), moa_filter=NormalisationFilter())\n", "add_noise_transformer = MOATransformer(schema=normalisation_transformer.get_schema(), moa_filter=AddNoiseFilter())\n", "\n", "# Creating a learner\n", "ob_learner = OnlineBagging(schema=add_noise_transformer.get_schema(), ensemble_size=5)\n", "\n", "# Creating a drift detector\n", "drift_detector = ADWIN()\n", "\n", "# Define a function that prepares the input of the drift detector\n", "def label_equals_prediction(instance: LabeledInstance, prediction: LabelIndex) -> LabelIndex:\n", " label = instance.y_index\n", " return int(label == prediction)\n", "\n", "# Creating and populating the transformation pipeline\n", "trafo_pipeline = (BasePipeline()\n", " .add_transformer(normalisation_transformer)\n", " .add_transformer(add_noise_transformer))\n", "\n", "# Creating and populating the prediction pipeline\n", "prediction_pipeline = ClassifierPipeline().add_classifier(ob_learner)\n", "\n", "# Creating and populating the drift detection pipeline\n", "drift_pipeline = BasePipeline().add_drift_detector(drift_detector, get_drift_detector_input_func=label_equals_prediction)\n", "\n", "# Since pipelines themselves are pipeline elements, we can pass them to the initializer of an overall pipeline object\n", "pipeline = ClassifierPipeline([trafo_pipeline, prediction_pipeline, drift_pipeline])\n", "\n", "# An alternative syntax would be\n", "# pipeline = (ClassifierPipeline()\n", "# .add_pipeline_element(trafo_pipeline)\n", "# .add_pipeline_element(prediction_pipeline)\n", "# .add_pipeline_element(drift_pipeline))\n", "\n", "# Creating the evaluator\n", "ob_evaluator = ClassificationEvaluator(schema=elec_stream.get_schema()) \n", "\n", "i = 0\n", "while elec_stream.has_more_instances():\n", " instance = elec_stream.next_instance()\n", " prediction = pipeline.predict(instance)\n", " ob_evaluator.update(instance.y_index, prediction)\n", " pipeline.train(instance)\n", " if drift_detector.detected_change():\n", " print(f\"Detected change at index {i}\")\n", " i += 1\n", "\n", "ob_evaluator.accuracy()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.9.19" } }, "nbformat": 4, "nbformat_minor": 5 }