diff --git a/docs/api/datasets/fetch_criteo.rst b/docs/api/datasets/fetch_criteo.rst index b3f72da..7a116d2 100644 --- a/docs/api/datasets/fetch_criteo.rst +++ b/docs/api/datasets/fetch_criteo.rst @@ -6,4 +6,16 @@ .. autofunction:: sklift.datasets.datasets.fetch_criteo -.. include:: ../../../sklift/datasets/descr/criteo.rst \ No newline at end of file +.. include:: ../../../sklift/datasets/descr/criteo.rst + +About Criteo +################## + +.. figure:: https://upload.wikimedia.org/wikipedia/commons/d/d2/Criteo_logo21.svg + +`Criteo `__ is an advertising company that provides online display advertisements. +The company was founded and is headquartered in Paris, France. Criteo's product is a form of display advertising, +which displays interactive banner advertisements, generated based on the online browsing preferences and behaviour for each customer. +The solution operates on a pay per click/cost per click (CPC) basis. + +Link to the company's website: https://www.criteo.com/ \ No newline at end of file diff --git a/docs/api/datasets/fetch_hillstrom.rst b/docs/api/datasets/fetch_hillstrom.rst index d71d722..8eb036f 100644 --- a/docs/api/datasets/fetch_hillstrom.rst +++ b/docs/api/datasets/fetch_hillstrom.rst @@ -6,4 +6,12 @@ .. autofunction:: sklift.datasets.datasets.fetch_hillstrom -.. include:: ../../../sklift/datasets/descr/hillstrom.rst \ No newline at end of file +.. include:: ../../../sklift/datasets/descr/hillstrom.rst + +About Hillstrom +################## + +The dataset was provided by Kevin Hillstorm. +Kevin is President of MineThatData, a consultancy that helps CEOs understand the complex relationship between Customers, Advertising, Products, Brands, and Channels. + +Link to the blog: https://blog.minethatdata.com/ \ No newline at end of file diff --git a/docs/api/datasets/fetch_lenta.rst b/docs/api/datasets/fetch_lenta.rst index dd2f225..65d5ecc 100644 --- a/docs/api/datasets/fetch_lenta.rst +++ b/docs/api/datasets/fetch_lenta.rst @@ -6,4 +6,14 @@ .. autofunction:: sklift.datasets.datasets.fetch_lenta -.. include:: ../../../sklift/datasets/descr/lenta.rst \ No newline at end of file +.. include:: ../../../sklift/datasets/descr/lenta.rst + +About Lenta +################## + +.. figure:: https://upload.wikimedia.org/wikipedia/commons/7/73/Lenta_logo.svg + +`Lenta (Russian: Лентa) `__ is a Russian super - and hypermarket chain. With 149 locations across the country, +it is one of Russia's largest retail chains in addition to being the country's second largest hypermarket chain. + +Link to the company's website: https://www.lenta.com/ \ No newline at end of file diff --git a/docs/api/datasets/fetch_megafon.rst b/docs/api/datasets/fetch_megafon.rst index 0829df8..8af63ea 100644 --- a/docs/api/datasets/fetch_megafon.rst +++ b/docs/api/datasets/fetch_megafon.rst @@ -6,4 +6,14 @@ .. autofunction:: sklift.datasets.datasets.fetch_megafon -.. include:: ../../../sklift/datasets/descr/megafon.rst \ No newline at end of file +.. include:: ../../../sklift/datasets/descr/megafon.rst + +About MegaFon +################## + +.. figure:: https://upload.wikimedia.org/wikipedia/commons/9/9e/MegaFon_logo.svg + +`MegaFon (Russian: МегаФон) `__ , previously known as North-West GSM, is the second largest mobile phone operator and the third largest telecom operator in Russia. +It works in the GSM, UMTS and LTE standard. As of June 2012, the company serves 62.1 million subscribers in Russia and 1.6 million in Tajikistan. It is headquartered in Moscow. + +Link to the company's website: https://megafon.ru/ \ No newline at end of file diff --git a/docs/api/datasets/fetch_x5.rst b/docs/api/datasets/fetch_x5.rst index cb42b2f..fdda3a7 100644 --- a/docs/api/datasets/fetch_x5.rst +++ b/docs/api/datasets/fetch_x5.rst @@ -6,4 +6,16 @@ .. autofunction:: sklift.datasets.datasets.fetch_x5 -.. include:: ../../../sklift/datasets/descr/x5.rst \ No newline at end of file +.. include:: ../../../sklift/datasets/descr/x5.rst + +About X5 +################## + +.. figure:: https://upload.wikimedia.org/wikipedia/en/8/83/X5_Retail_Group_logo_2015.png + +`X5 Group `__ is a leading Russian food retailer. +The Company operates several retail formats: proximity stores under the Pyaterochka brand, +supermarkets under the Perekrestok brand and hypermarkets under the Karusel brand, as well as the Perekrestok.ru online market, +the 5Post parcel and Dostavka.Pyaterochka and Perekrestok. Bystro food delivery services. + +Link to the company's website: https://www.x5.ru/ \ No newline at end of file diff --git a/docs/changelog.md b/docs/changelog.md index 642b1fc..849f5d2 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -8,6 +8,13 @@ * 🔨 something that previously didn’t work as documented – or according to reasonable expectations – should now work. * ❗️ you will need to change your code to have the same effect in the future; or a feature will be removed in the future. +## Version 0.4.1 + +### [sklift.datasets](https://www.uplift-modeling.com/en/v0.4.0/api/datasets/index.html) + +* 🔨 Fix bug in dataset links. +* 📝 Add about a company section + ## Version 0.4.0 ### [sklift.metrics](https://www.uplift-modeling.com/en/v0.4.0/api/index/metrics.html) diff --git a/notebooks/uplift_metrics_tutorial_advanced.ipynb b/notebooks/uplift_metrics_tutorial_advanced.ipynb new file mode 100644 index 0000000..9906d35 --- /dev/null +++ b/notebooks/uplift_metrics_tutorial_advanced.ipynb @@ -0,0 +1,2166 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "accelerator": "GPU", + "colab": { + "name": "uplift_metrics_tutorial_advanced.ipynb", + "provenance": [], + "collapsed_sections": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "sklift-env", + "language": "python", + "name": "sklift-env" + }, + "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.7.1" + }, + "pycharm": { + "stem_cell": { + "cell_type": "raw", + "metadata": { + "collapsed": false + }, + "source": [] + } + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "12a2acaf31694c63a2813f34d37300dd": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HBoxModel", + "model_module_version": "1.5.0", + "state": { + "_view_name": "HBoxView", + "_dom_classes": [], + "_model_name": "HBoxModel", + "_view_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_view_count": null, + "_view_module_version": "1.5.0", + "box_style": "", + "layout": "IPY_MODEL_7553ee7087e245e694f7f85837e088ec", + "_model_module": "@jupyter-widgets/controls", + "children": [ + "IPY_MODEL_60d81df4c86240999f4be223efec1533", + "IPY_MODEL_db7f043fbefb4dcda7d3486cffd28faf", + "IPY_MODEL_f7418cb987f9437c9627dceea703ecd6" + ] + } + }, + "7553ee7087e245e694f7f85837e088ec": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_view_name": "LayoutView", + "grid_template_rows": null, + "right": null, + "justify_content": null, + "_view_module": "@jupyter-widgets/base", + "overflow": null, + "_model_module_version": "1.2.0", + "_view_count": null, + "flex_flow": null, + "width": null, + "min_width": null, + "border": null, + "align_items": null, + "bottom": null, + "_model_module": "@jupyter-widgets/base", + "top": null, + "grid_column": null, + "overflow_y": null, + "overflow_x": null, + "grid_auto_flow": null, + "grid_area": null, + "grid_template_columns": null, + "flex": null, + "_model_name": "LayoutModel", + "justify_items": null, + "grid_row": null, + "max_height": null, + "align_content": null, + "visibility": null, + "align_self": null, + "height": null, + "min_height": null, + "padding": null, + "grid_auto_rows": null, + "grid_gap": null, + "max_width": null, + "order": null, + "_view_module_version": "1.2.0", + "grid_template_areas": null, + "object_position": null, + "object_fit": null, + "grid_auto_columns": null, + "margin": null, + "display": null, + "left": null + } + }, + "60d81df4c86240999f4be223efec1533": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_view_name": "HTMLView", + "style": "IPY_MODEL_9f9467cab1f2430fa89e2fc396ced9f8", + "_dom_classes": [], + "description": "", + "_model_name": "HTMLModel", + "placeholder": "​", + "_view_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "value": "100%", + "_view_count": null, + "_view_module_version": "1.5.0", + "description_tooltip": null, + "_model_module": "@jupyter-widgets/controls", + "layout": "IPY_MODEL_ecf054c1199c45389e7dbf94c5ac41df" + } + }, + "db7f043fbefb4dcda7d3486cffd28faf": { + "model_module": "@jupyter-widgets/controls", + "model_name": "FloatProgressModel", + "model_module_version": "1.5.0", + "state": { + "_view_name": "ProgressView", + "style": "IPY_MODEL_f309aeffa2824070afc241d3477c6bcd", + "_dom_classes": [], + "description": "", + "_model_name": "FloatProgressModel", + "bar_style": "", + "max": 144735744, + "_view_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "value": 144735744, + "_view_count": null, + "_view_module_version": "1.5.0", + "orientation": "horizontal", + "min": 0, + "description_tooltip": null, + "_model_module": "@jupyter-widgets/controls", + "layout": "IPY_MODEL_353821f9d47f4434b71b956c3946ad01" + } + }, + "f7418cb987f9437c9627dceea703ecd6": { + "model_module": "@jupyter-widgets/controls", + "model_name": "HTMLModel", + "model_module_version": "1.5.0", + "state": { + "_view_name": "HTMLView", + "style": "IPY_MODEL_60a724915a0a4c9f86197e8b7066b513", + "_dom_classes": [], + "description": "", + "_model_name": "HTMLModel", + "placeholder": "​", + "_view_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "value": " 145M/145M [00:20<00:00, 29.6MiB/s]", + "_view_count": null, + "_view_module_version": "1.5.0", + "description_tooltip": null, + "_model_module": "@jupyter-widgets/controls", + "layout": "IPY_MODEL_16efe430cd6a4b608dd690598ece62cb" + } + }, + "9f9467cab1f2430fa89e2fc396ced9f8": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_view_name": "StyleView", + "_model_name": "DescriptionStyleModel", + "description_width": "", + "_view_module": "@jupyter-widgets/base", + "_model_module_version": "1.5.0", + "_view_count": null, + "_view_module_version": "1.2.0", + "_model_module": "@jupyter-widgets/controls" + } + }, + "ecf054c1199c45389e7dbf94c5ac41df": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_view_name": "LayoutView", + "grid_template_rows": null, + "right": null, + "justify_content": null, + "_view_module": "@jupyter-widgets/base", + "overflow": null, + "_model_module_version": "1.2.0", + "_view_count": null, + "flex_flow": null, + "width": null, + "min_width": null, + "border": null, + "align_items": null, + "bottom": null, + "_model_module": "@jupyter-widgets/base", + "top": null, + "grid_column": null, + "overflow_y": null, + "overflow_x": null, + "grid_auto_flow": null, + "grid_area": null, + "grid_template_columns": null, + "flex": null, + "_model_name": "LayoutModel", + "justify_items": null, + "grid_row": null, + "max_height": null, + "align_content": null, + "visibility": null, + "align_self": null, + "height": null, + "min_height": null, + "padding": null, + "grid_auto_rows": null, + "grid_gap": null, + "max_width": null, + "order": null, + "_view_module_version": "1.2.0", + "grid_template_areas": null, + "object_position": null, + "object_fit": null, + "grid_auto_columns": null, + "margin": null, + "display": null, + "left": null + } + }, + "f309aeffa2824070afc241d3477c6bcd": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ProgressStyleModel", + "model_module_version": "1.5.0", + "state": { + "_view_name": "StyleView", + "_model_name": "ProgressStyleModel", + "description_width": "", + "_view_module": "@jupyter-widgets/base", + "_model_module_version": "1.5.0", + "_view_count": null, + "_view_module_version": "1.2.0", + "bar_color": null, + "_model_module": "@jupyter-widgets/controls" + } + }, + "353821f9d47f4434b71b956c3946ad01": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_view_name": "LayoutView", + "grid_template_rows": null, + "right": null, + "justify_content": null, + "_view_module": "@jupyter-widgets/base", + "overflow": null, + "_model_module_version": "1.2.0", + "_view_count": null, + "flex_flow": null, + "width": null, + "min_width": null, + "border": null, + "align_items": null, + "bottom": null, + "_model_module": "@jupyter-widgets/base", + "top": null, + "grid_column": null, + "overflow_y": null, + "overflow_x": null, + "grid_auto_flow": null, + "grid_area": null, + "grid_template_columns": null, + "flex": null, + "_model_name": "LayoutModel", + "justify_items": null, + "grid_row": null, + "max_height": null, + "align_content": null, + "visibility": null, + "align_self": null, + "height": null, + "min_height": null, + "padding": null, + "grid_auto_rows": null, + "grid_gap": null, + "max_width": null, + "order": null, + "_view_module_version": "1.2.0", + "grid_template_areas": null, + "object_position": null, + "object_fit": null, + "grid_auto_columns": null, + "margin": null, + "display": null, + "left": null + } + }, + "60a724915a0a4c9f86197e8b7066b513": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_view_name": "StyleView", + "_model_name": "DescriptionStyleModel", + "description_width": "", + "_view_module": "@jupyter-widgets/base", + "_model_module_version": "1.5.0", + "_view_count": null, + "_view_module_version": "1.2.0", + "_model_module": "@jupyter-widgets/controls" + } + }, + "16efe430cd6a4b608dd690598ece62cb": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_view_name": "LayoutView", + "grid_template_rows": null, + "right": null, + "justify_content": null, + "_view_module": "@jupyter-widgets/base", + "overflow": null, + "_model_module_version": "1.2.0", + "_view_count": null, + "flex_flow": null, + "width": null, + "min_width": null, + "border": null, + "align_items": null, + "bottom": null, + "_model_module": "@jupyter-widgets/base", + "top": null, + "grid_column": null, + "overflow_y": null, + "overflow_x": null, + "grid_auto_flow": null, + "grid_area": null, + "grid_template_columns": null, + "flex": null, + "_model_name": "LayoutModel", + "justify_items": null, + "grid_row": null, + "max_height": null, + "align_content": null, + "visibility": null, + "align_self": null, + "height": null, + "min_height": null, + "padding": null, + "grid_auto_rows": null, + "grid_gap": null, + "max_width": null, + "order": null, + "_view_module_version": "1.2.0", + "grid_template_areas": null, + "object_position": null, + "object_fit": null, + "grid_auto_columns": null, + "margin": null, + "display": null, + "left": null + } + } + } + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "ATqE_EOoymEd" + }, + "source": [ + "# 🎯 Uplift modeling `metrics` advanced\n", + "\n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + " SCIKIT-UPLIFT REPO | \n", + " SCIKIT-UPLIFT DOCS | \n", + " USER GUIDE\n", + "
\n", + "
" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "jmg3AprtymEg" + }, + "source": [ + "import sys\n", + "\n", + "# install uplift library scikit-uplift and other libraries \n", + "!{sys.executable} -m pip install scikit-uplift dill catboost\n", + "from IPython.display import clear_output\n", + "clear_output()" + ], + "execution_count": 1, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cHFiqvnrymEh" + }, + "source": [ + "# 📝 Load data\n", + "\n", + "We are going to use a `Lenta dataset` from the BigTarget Hackathon hosted in summer 2020 by Lenta and Microsoft.\n", + "\n", + "Lenta is a russian food retailer. \n", + "\n", + "### Data description\n", + "\n", + "✏️ Dataset can be loaded from `sklift.datasets` module using `fetch_lenta` function.\n", + "\n", + "Read more about dataset in the api docs. \n", + "\n", + "This is an uplift modeling dataset containing data about Lenta's customers grociery shopping, marketing campaigns communications as `treatment` and store visits as `target`.\n", + "\n", + "#### ✏️ Major columns:\n", + "\n", + "- `group` - treatment / control flag\n", + "- `response_att` - binary target\n", + "- `CardHolder` - customer id\n", + "- `gender` - customer gender \n", + "- `age` - customer age" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "5o0Hm-iqymEi", + "scrolled": true, + "colab": { + "base_uri": "https://localhost:8080/", + "height": 49, + "referenced_widgets": [ + "12a2acaf31694c63a2813f34d37300dd", + "7553ee7087e245e694f7f85837e088ec", + "60d81df4c86240999f4be223efec1533", + "db7f043fbefb4dcda7d3486cffd28faf", + "f7418cb987f9437c9627dceea703ecd6", + "9f9467cab1f2430fa89e2fc396ced9f8", + "ecf054c1199c45389e7dbf94c5ac41df", + "f309aeffa2824070afc241d3477c6bcd", + "353821f9d47f4434b71b956c3946ad01", + "60a724915a0a4c9f86197e8b7066b513", + "16efe430cd6a4b608dd690598ece62cb" + ] + }, + "outputId": "233891ac-d09c-440f-8d54-50ea3ebfc3cd" + }, + "source": [ + "from sklift.datasets import fetch_lenta\n", + "\n", + "# returns sklearn Bunch object\n", + "# with data, target, treatment keys\n", + "# data features (pd.DataFrame), target (pd.Series), treatment (pd.Series) values \n", + "dataset = fetch_lenta()" + ], + "execution_count": 2, + "outputs": [ + { + "output_type": "display_data", + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "12a2acaf31694c63a2813f34d37300dd", + "version_minor": 0, + "version_major": 2 + }, + "text/plain": [ + " 0%| | 0.00/145M [00:00\n", + "\n", + "Dataset features shape: (687029, 193)\n", + "Dataset target shape: (687029,)\n", + "Dataset treatment shape: (687029,)\n" + ], + "name": "stdout" + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "F4-jlzDbymEk" + }, + "source": [ + "# 📝 EDA" + ] + }, + { + "cell_type": "code", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 406 + }, + "id": "t7kA0MxxymEk", + "outputId": "d5d5637e-ce85-4fcb-eb8c-695733919b99" + }, + "source": [ + "dataset.data.head().append(dataset.data.tail())" + ], + "execution_count": 4, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
agecheque_count_12m_g20cheque_count_12m_g21cheque_count_12m_g25cheque_count_12m_g32cheque_count_12m_g33cheque_count_12m_g38cheque_count_12m_g39cheque_count_12m_g41cheque_count_12m_g42cheque_count_12m_g45cheque_count_12m_g46cheque_count_12m_g48cheque_count_12m_g52cheque_count_12m_g56cheque_count_12m_g57cheque_count_12m_g58cheque_count_12m_g79cheque_count_3m_g20cheque_count_3m_g21cheque_count_3m_g25cheque_count_3m_g42cheque_count_3m_g45cheque_count_3m_g52cheque_count_3m_g56cheque_count_3m_g57cheque_count_3m_g79cheque_count_6m_g20cheque_count_6m_g21cheque_count_6m_g25cheque_count_6m_g32cheque_count_6m_g33cheque_count_6m_g38cheque_count_6m_g39cheque_count_6m_g40cheque_count_6m_g41cheque_count_6m_g42cheque_count_6m_g45cheque_count_6m_g46cheque_count_6m_g48...perdelta_days_between_visits_15_30dpromo_share_15dresponse_smsresponse_vibersale_count_12m_g32sale_count_12m_g33sale_count_12m_g49sale_count_12m_g54sale_count_12m_g57sale_count_3m_g24sale_count_3m_g33sale_count_3m_g57sale_count_6m_g24sale_count_6m_g25sale_count_6m_g32sale_count_6m_g33sale_count_6m_g44sale_count_6m_g54sale_count_6m_g57sale_sum_12m_g24sale_sum_12m_g25sale_sum_12m_g26sale_sum_12m_g27sale_sum_12m_g32sale_sum_12m_g44sale_sum_12m_g54sale_sum_3m_g24sale_sum_3m_g26sale_sum_3m_g32sale_sum_3m_g33sale_sum_6m_g24sale_sum_6m_g25sale_sum_6m_g26sale_sum_6m_g32sale_sum_6m_g33sale_sum_6m_g44sale_sum_6m_g54stdev_days_between_visits_15dstdev_discount_depth_15dstdev_discount_depth_1m
047.03.022.019.03.028.08.07.06.01.013.012.016.03.015.011.00.04.00.07.08.00.05.01.06.06.01.00.012.09.01.06.04.02.05.01.00.05.05.06.0...1.33930.58210.9230770.07142910.084.31498.016.011.0137.28228.7766.0169.65810.6807.028.77621.08.09.04469.86658.851286.327736.05418.803233.31811.732321.61182.82283.843648.233141.25356.67237.25283.843648.231195.37535.421.70780.27980.3008
157.01.00.02.01.01.01.00.01.00.01.00.01.00.00.00.00.01.00.00.02.00.01.00.00.00.01.01.00.02.01.01.01.00.03.01.00.01.00.01.0...0.00000.00001.0000000.0000001.01.0002.02.00.00.0001.0000.01.7442.0001.01.0000.02.00.0113.3962.6958.7193.3587.010.00122.980.0058.7187.01179.83113.3962.6958.7187.01179.830.00122.980.00000.00000.0000
238.07.00.015.04.09.05.09.014.07.06.010.014.05.011.00.03.02.02.00.03.02.01.01.00.00.02.06.00.09.02.05.01.07.07.08.03.02.06.06.0...0.00000.72561.0000000.2500005.021.10250.0109.00.00.0007.5940.025.29411.0843.011.15831.059.00.01564.91971.09177.933257.49975.212555.276351.290.000.000.00783.871239.19533.4683.37593.131217.431336.833709.820.0000NaN0.0803
365.06.03.025.02.010.014.011.08.01.00.02.06.07.02.00.00.00.01.00.05.00.00.01.00.00.00.02.01.011.02.03.05.05.04.02.01.00.01.03.0...0.00000.00000.9090910.0000002.012.54449.039.00.00.0002.7780.02.00034.2122.03.7782.013.00.0358.223798.18680.931425.07175.73602.813544.760.00119.9973.24346.74139.681849.91360.40175.73496.73172.581246.210.00000.00000.0000
461.00.01.02.00.02.01.00.03.02.01.01.05.05.00.00.00.01.00.01.01.00.00.02.00.00.01.00.01.02.00.02.01.00.08.02.02.01.01.04.0...0.00000.78651.0000000.1000000.01.45425.025.00.00.0000.4540.03.03612.0000.01.4548.023.00.0226.98168.05960.371560.210.00342.451039.850.0066.180.0087.94226.98168.05461.370.00237.93225.51995.271.41420.34950.3495
68702435.00.00.04.00.02.00.01.00.03.02.02.03.02.01.00.01.00.00.00.03.02.01.02.01.00.00.00.00.03.00.02.00.00.05.00.02.02.02.02.0...1.33330.40020.0000000.1666670.03.00014.02.00.019.8563.0000.019.85629.0000.03.00015.01.00.0550.09695.32111.87114.210.001173.84147.68550.09111.870.00330.96550.09669.33111.870.00330.961173.84119.992.64580.36460.3282
68702533.00.00.00.00.00.00.00.00.00.00.00.02.00.00.00.00.00.0NaNNaNNaNNaNNaNNaNNaNNaNNaN0.00.00.00.00.00.00.01.00.00.00.00.02.0...0.00000.00001.0000000.0000000.00.0001.01.00.0NaNNaNNaN0.0000.0000.00.0000.01.00.00.000.000.000.000.000.0028.01NaNNaNNaNNaN0.000.000.000.000.000.0028.010.00000.00000.0000
68702636.00.00.03.00.00.00.00.01.00.00.01.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.0...0.00000.98471.0000000.0000000.00.0005.03.00.00.0000.0000.00.0000.0000.00.00015.00.00.00.00155.9723.9941.510.00615.7787.470.000.000.000.000.000.000.000.000.00449.010.000.0000NaNNaN
68702737.00.01.02.00.00.00.00.00.01.00.01.00.01.00.00.00.00.00.00.01.00.00.01.00.00.00.00.00.01.00.00.00.00.01.00.00.00.00.00.0...0.00000.83181.0000000.0000000.00.0001.00.00.00.0000.0000.00.0000.4760.00.0000.00.00.00.0081.9029.820.000.000.000.000.000.000.000.000.0046.720.000.000.000.000.000.0000NaNNaN
68702840.00.01.00.00.02.00.00.02.02.02.02.03.01.01.02.01.04.00.01.00.01.00.00.01.01.03.00.01.00.00.01.00.00.00.00.01.00.02.02.0...0.00000.00001.0000000.1000000.06.45225.017.03.06.6601.3441.06.6600.0000.01.34418.04.01.0531.250.000.00916.440.002407.561304.03290.010.000.00228.47290.010.000.000.00228.47752.32596.860.00000.00000.0000
\n", + "

10 rows × 193 columns

\n", + "
" + ], + "text/plain": [ + " age ... stdev_discount_depth_1m\n", + "0 47.0 ... 0.3008\n", + "1 57.0 ... 0.0000\n", + "2 38.0 ... 0.0803\n", + "3 65.0 ... 0.0000\n", + "4 61.0 ... 0.3495\n", + "687024 35.0 ... 0.3282\n", + "687025 33.0 ... 0.0000\n", + "687026 36.0 ... NaN\n", + "687027 37.0 ... NaN\n", + "687028 40.0 ... 0.0000\n", + "\n", + "[10 rows x 193 columns]" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cNSQsJcqymEk" + }, + "source": [ + "### 🤔 target share for `treatment / control` " + ] + }, + { + "cell_type": "code", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 142 + }, + "id": "d0BPrhjnymEl", + "outputId": "a57f8423-1dd4-42ed-f2d4-63b939077770" + }, + "source": [ + "import pandas as pd \n", + "\n", + "pd.crosstab(dataset.treatment, dataset.target, normalize='index')" + ], + "execution_count": 5, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
response_att01
group
control0.8974210.102579
test0.8898740.110126
\n", + "
" + ], + "text/plain": [ + "response_att 0 1\n", + "group \n", + "control 0.897421 0.102579\n", + "test 0.889874 0.110126" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "q48zr_exymEl" + }, + "source": [ + "# make treatment binary\n", + "treat_dict = {\n", + " 'test': 1,\n", + " 'control': 0\n", + "}\n", + "\n", + "dataset.treatment = dataset.treatment.map(treat_dict)" + ], + "execution_count": 6, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "9oGypq_JymEm", + "outputId": "90909780-1bb9-4166-90a2-1f343803959e" + }, + "source": [ + "# fill NaNs in the categorical feature `gender` \n", + "# for CatBoostClassifier\n", + "dataset.data['gender'] = dataset.data['gender'].fillna(value='Не определен')\n", + "\n", + "print(dataset.data['gender'].value_counts(dropna=False))" + ], + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "text": [ + "Ж 433448\n", + "М 243910\n", + "Не определен 9671\n", + "Name: gender, dtype: int64\n" + ], + "name": "stdout" + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MKHT1JzsymEm" + }, + "source": [ + "### ✂️ train test split\n", + "\n", + "- stratify by two columns: treatment and target. \n", + "\n", + "`Intuition:` In a binary classification problem definition we stratify train set by splitting target `0/1` column. In uplift modeling we have two columns instead of one. " + ] + }, + { + "cell_type": "code", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "u4lM58UMymEm", + "outputId": "84cc2abf-b854-41a4-8bb8-bbddeb97baab" + }, + "source": [ + "from sklearn.model_selection import train_test_split\n", + "\n", + "stratify_cols = pd.concat([dataset.treatment, dataset.target], axis=1)\n", + "\n", + "X_train, X_val, trmnt_train, trmnt_val, y_train, y_val = train_test_split(\n", + " dataset.data,\n", + " dataset.treatment,\n", + " dataset.target,\n", + " stratify=stratify_cols,\n", + " test_size=0.3,\n", + " random_state=42\n", + ")\n", + "\n", + "print(f\"Train shape: {X_train.shape}\")\n", + "print(f\"Validation shape: {X_val.shape}\")" + ], + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "text": [ + "Train shape: (480920, 193)\n", + "Validation shape: (206109, 193)\n" + ], + "name": "stdout" + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BYzpcKwuymEn" + }, + "source": [ + "# 👾 Class Transformation uplift model and Two Models\n", + "\n", + "### For example, let's take the models [ Class Transformation ](https://github.com/maks-sh/scikit-uplift/blob/c9dd56aa0277e81ef7c4be62bf2fd33432e46f36/sklift/models/models.py#L181) and [Two Models](https://github.com/maks-sh/scikit-uplift/blob/c9dd56aa0277e81ef7c4be62bf2fd33432e46f36/sklift/models/models.py#L271). Let's display their uplift scores on one graph" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "PBwZVdIEymEn" + }, + "source": [ + "from catboost import CatBoostClassifier\n", + "from sklearn.base import clone\n", + "\n", + "from sklift.models import TwoModels\n", + "from sklift.models import ClassTransformation\n", + "\n", + "first_estimator = CatBoostClassifier(verbose=100,\n", + " task_type=\"GPU\",\n", + " devices='0:1',\n", + " cat_features=['gender'],\n", + " random_state=42,\n", + " thread_count=1)\n", + "second_estimator = clone(first_estimator)\n", + "\n", + "transform_model = ClassTransformation(estimator=first_estimator)\n", + "two_model = TwoModels(estimator_trmnt=first_estimator, estimator_ctrl=second_estimator)" + ], + "execution_count": 9, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "6IcMWundymEn", + "outputId": "5f59657c-2a7d-47aa-cb21-89a900e47e23" + }, + "source": [ + "transform_model = transform_model.fit(\n", + " X=X_train, \n", + " y=y_train, \n", + " treatment=trmnt_train\n", + ")\n", + "\n", + "two_model = two_model.fit(\n", + " X=X_train, \n", + " y=y_train, \n", + " treatment=trmnt_train\n", + ")" + ], + "execution_count": 10, + "outputs": [ + { + "output_type": "stream", + "text": [ + "Learning rate set to 0.024003\n", + "0:\tlearn: 0.6893849\ttotal: 59ms\tremaining: 58.9s\n", + "100:\tlearn: 0.6100331\ttotal: 5.39s\tremaining: 48s\n", + "200:\tlearn: 0.6019326\ttotal: 12s\tremaining: 47.8s\n", + "300:\tlearn: 0.6000429\ttotal: 18.7s\tremaining: 43.4s\n", + "400:\tlearn: 0.5992161\ttotal: 25.4s\tremaining: 37.9s\n", + "500:\tlearn: 0.5986674\ttotal: 32s\tremaining: 31.8s\n", + "600:\tlearn: 0.5982996\ttotal: 38.5s\tremaining: 25.5s\n", + "700:\tlearn: 0.5980941\ttotal: 44.8s\tremaining: 19.1s\n", + "800:\tlearn: 0.5979237\ttotal: 51.2s\tremaining: 12.7s\n", + "900:\tlearn: 0.5976503\ttotal: 57.5s\tremaining: 6.32s\n", + "999:\tlearn: 0.5975015\ttotal: 1m 3s\tremaining: 0us\n", + "Learning rate set to 0.02591\n", + "0:\tlearn: 0.6711650\ttotal: 23.1ms\tremaining: 23.1s\n", + "100:\tlearn: 0.2887976\ttotal: 3.03s\tremaining: 27s\n", + "200:\tlearn: 0.2763838\ttotal: 6.53s\tremaining: 26s\n", + "300:\tlearn: 0.2729584\ttotal: 10.2s\tremaining: 23.7s\n", + "400:\tlearn: 0.2713649\ttotal: 13.9s\tremaining: 20.8s\n", + "500:\tlearn: 0.2703728\ttotal: 17.6s\tremaining: 17.6s\n", + "600:\tlearn: 0.2696703\ttotal: 21.3s\tremaining: 14.1s\n", + "700:\tlearn: 0.2691328\ttotal: 24.9s\tremaining: 10.6s\n", + "800:\tlearn: 0.2686616\ttotal: 28.6s\tremaining: 7.11s\n", + "900:\tlearn: 0.2682632\ttotal: 32.3s\tremaining: 3.55s\n", + "999:\tlearn: 0.2678762\ttotal: 36s\tremaining: 0us\n", + "Learning rate set to 0.024384\n", + "0:\tlearn: 0.6735712\ttotal: 44.9ms\tremaining: 44.9s\n", + "100:\tlearn: 0.3063022\ttotal: 4.82s\tremaining: 42.9s\n", + "200:\tlearn: 0.2925770\ttotal: 10.2s\tremaining: 40.4s\n", + "300:\tlearn: 0.2895685\ttotal: 15.6s\tremaining: 36.3s\n", + "400:\tlearn: 0.2880540\ttotal: 21.3s\tremaining: 31.9s\n", + "500:\tlearn: 0.2872389\ttotal: 26.9s\tremaining: 26.8s\n", + "600:\tlearn: 0.2866951\ttotal: 32.6s\tremaining: 21.6s\n", + "700:\tlearn: 0.2863474\ttotal: 38.1s\tremaining: 16.3s\n", + "800:\tlearn: 0.2860138\ttotal: 43.6s\tremaining: 10.8s\n", + "900:\tlearn: 0.2857359\ttotal: 49.2s\tremaining: 5.41s\n", + "999:\tlearn: 0.2854954\ttotal: 54.8s\tremaining: 0us\n" + ], + "name": "stdout" + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "POrn2kgwymEo" + }, + "source": [ + "### Uplift prediction" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "Xx_hHajjymEo" + }, + "source": [ + "uplift_transform_model_val = transform_model.predict(X_val)\n", + "uplift_transform_model_train = transform_model.predict(X_train)\n", + "\n", + "uplift_two_model = two_model.predict(X_val)" + ], + "execution_count": 11, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-5PofV6aymEp" + }, + "source": [ + "# 🚀🚀🚀 Uplift metrics" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SmvFxIALymEp" + }, + "source": [ + "### 🚀 `uplift@k`\n", + "\n", + "- uplift at first k%\n", + "- usually falls between [0; 1] depending on k, model quality and data\n", + "\n", + "\n", + "### `uplift@k` = `target mean at k% in the treatment group` - `target mean at k% in the control group`\n", + "\n", + "___\n", + "\n", + "How to count `uplift@k`:\n", + "\n", + "1. sort by predicted uplift\n", + "2. select first k%\n", + "3. count target mean in the treatment group\n", + "4. count target mean in the control group\n", + "5. substract the mean in the control group from the mean in the treatment group\n", + "\n", + "---\n", + "\n", + "Code parameter options:\n", + "\n", + "- `strategy='overall'` - sort by uplift treatment and control together\n", + "- `strategy='by_group'` - sort by uplift treatment and control separately" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KWBOEv0Z6daH" + }, + "source": [ + "## `🚀uplift@k with a small step ot the k parameter`\n", + "\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "ZWjC06aQymEp" + }, + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "from sklift.metrics import uplift_at_k\n", + "\n", + "values_uplift_k_transform = []\n", + "values_uplift_k_two = []\n", + "values_k = []\n", + "for k in np.arange(0.01,1,0.01):\n", + " values_uplift_k_transform.append(uplift_at_k(y_val, uplift_transform_model_val, trmnt_val, strategy='overall', k=k))\n", + " values_uplift_k_two.append(uplift_at_k(y_val, uplift_two_model, trmnt_val, strategy='overall', k=k))\n", + " values_k.append(k)" + ], + "execution_count": 12, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "oshHc_VWlKmw" + }, + "source": [ + "### `For ClassTransformation model`" + ] + }, + { + "cell_type": "code", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 295 + }, + "id": "O6tfXwaLlHJV", + "outputId": "03c001f3-b386-4838-a6dd-e7a215b235f2" + }, + "source": [ + "plt.plot(values_k, values_uplift_k_transform)\n", + "plt.title('Dependence of uplift@k on k')\n", + "plt.xlabel('The value of k')\n", + "plt.ylabel('The value of uplift@k')\n", + "plt.show()" + ], + "execution_count": 13, + "outputs": [ + { + "output_type": "display_data", + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + } + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7eRHptiLlXpb" + }, + "source": [ + "### `For TwoModels`" + ] + }, + { + "cell_type": "code", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 295 + }, + "id": "lQGkD3dTlEQn", + "outputId": "ff2debcb-030e-4158-ed64-24216a341985" + }, + "source": [ + "plt.plot(values_k, values_uplift_k_two)\n", + "plt.title('Dependence of uplift@k on k')\n", + "plt.xlabel('The value of k')\n", + "plt.ylabel('The value of uplift@k')\n", + "plt.show()" + ], + "execution_count": 14, + "outputs": [ + { + "output_type": "display_data", + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + } + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KD5ZUzlEJN1b" + }, + "source": [ + "# 🚀 `ASD metric`\n", + "### `The average squared deviation (ASD) is a model stability metric that shows how much the model overfits the training data. Larger values of ASD mean greater overfit.`\n", + "\n", + "## Code parameter options:\n", + "\n", + "- `strategy='overall'` - The first step is taking the first k observations of all test data ordered by uplift prediction (overall both groups - control and treatment) and conversions in treatment and control groups calculated only on them. Then the difference between these conversions is calculated.\n", + "- `strategy='by_group'` - Separately calculates conversions in top k observations in each group (control and treatment) sorted by uplift predictions. Then the difference between these conversions is calculated\n", + "- `bins=10` - Determines the number of bins (and the relative percentile) in the data." + ] + }, + { + "cell_type": "code", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "FnqffihzymEv", + "outputId": "30a329cc-387b-4500-8c3e-f8f6ab043f37" + }, + "source": [ + "from sklift.metrics import average_squared_deviation\n", + "\n", + "asd_overall = average_squared_deviation(y_train, uplift_transform_model_train, trmnt_train, y_val,\n", + " uplift_transform_model_val, trmnt_val, strategy='overall')\n", + "asd_by_group = average_squared_deviation(y_train, uplift_transform_model_train, trmnt_train, y_val, \n", + " uplift_transform_model_val, trmnt_val, strategy='by_group')\n", + "\n", + "print(f\"average squared deviation by overall strategy for the ClassTransformation model: {asd_overall:.6f}\")\n", + "print(f\"average squared deviation by group strategy for the ClassTransformation model: {asd_by_group:.6f}\")" + ], + "execution_count": 15, + "outputs": [ + { + "output_type": "stream", + "text": [ + "average squared deviation by overall strategy for the ClassTransformation model: 0.000007\n", + "average squared deviation by group strategy for the ClassTransformation model: 0.000011\n" + ], + "name": "stdout" + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VSg7zXHGG_76" + }, + "source": [ + "# `↗️Display 2 different model uplift scores on one qini plot`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BrRjY_zlYThJ" + }, + "source": [ + "### `Only qiwi curves`" + ] + }, + { + "cell_type": "code", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 296 + }, + "id": "-WFTIgynAI28", + "outputId": "b37fb698-7522-44ac-c786-21ea6f8e21a7" + }, + "source": [ + "from sklift.viz import plot_qini_curve\n", + "\n", + "fig, ax_roc = plt.subplots(1, 1)\n", + "plot_qini_curve(y_val, uplift_transform_model_val, trmnt_val, name='Transform model', random=False, perfect=False, ax=ax_roc)\n", + "plot_qini_curve(y_val, uplift_two_model, trmnt_val, name='Two models', random=False, perfect=False, ax=ax_roc)" + ], + "execution_count": 16, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "execution_count": 16 + }, + { + "output_type": "display_data", + "data": { + "image/png": "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7jnnz5/3rFOnTm779u0vLF68OMiZGDt37tzm/PnznvnLJ02adPj222+36/6rV69e9sGDB71btGhx8eLFi6Snp3vWq1cvx7ZOkyZN7FqUjhw5YtfiVJgLFy4oX19fU3H1bLll0LdS6hUgByizH4O01jO01lFa66iQkJCyeqwQQriebXfcze87d8/AD+HRta6Jp5JJTU31bNy4cTbAZ599Vqe4+snJyV65ubkMGzbs3Ntvv520a9euAuOyevfunb5ixYpaaWlpHqmpqR4rVqwI6t27d7HjecpKcHBwbkBAQO7KlStrAMyaNSu4W7du6XXq1MmtWbNm7qpVq2oAfPXVV7Ut99xwww0p06ZNC7F0o+3cudMnNTW10O/z7du3z7JNNr777rvaH330UWJSUtKupKSkXQkJCbs2btwYkJaW5tG3b9/0VatWBZ49e9YDYPbs2bXCw8MzvLy8uOWWW9Kys7PV+++/n/d7/9dff/lZYre1bdu2vZZB+7af/MkSwIABA8598cUXwQBffvllULdu3dJsxy8B9OrV63xCQoJvbGysd2Zmplq0aFHtu+6661xxv7979+71jYiIKNE4q3JPmJRSwzAGgw/VOu9/iSSgiU21xuaywsqFEKLqSNyUd5gb9QhjOmzgjupfF31P1MNQz+EODpedUaNGHRs/fnzjK664om1OTk6x9RMSEqr16NGjTXh4eNv777+/+Ztvvnkkf50ePXpk3Hvvvac7dep0RefOna+4//77TxY2iNhVvvzyy4OjRo1q3Lp167Y7d+70mzRp0lGAWbNmJTzzzDOh4eHhbbXWea1Rzz///Knw8PDM9u3bX9GqVauIRx99tKlt92R+AQEBptDQ0Kzdu3f7pKWleaxfvz7Q0jVouR4VFZU+b968wKuvvvrCo48+eqJr167h4eHhbWfMmBHyxRdfJIDRKrZ06dL9a9asCWjSpEm7li1bRowaNapRo0aNLmkK47PPPnvq7NmzXqGhoe0+/vjj+u+///4RMP78evXq1RKMsU2TJ08+1K9fv9atWrWKuP32289ERUVlArz11lt169Wr1+H48ePekZGRbYcMGdLU8uz169fXvP3220u0iJnS+QcaliHzGKZlNrPk+gEfAL201idt6kUAczHGLTUEVgOtAIUxOLwvRqL0N3Cv1jq6qPdGRUXprVu3lvUvRwghXGN6Dzi2C4CwzLl5xQm+9xZ+z3jz//UO1mHS486hSjFjTim1TWsdZVu2Y8eOhMjIyCJnWonKa86cObW2bt3qP3Xq1KPujqW8HD582Gvw4MHNN2/eHOfo+o4dO+pERkaG5S93WQuTUuo7YDPQRil1RCk1HPgfUBP4VSn1r1JqOoA5AVqAMZh7JfC01jpXa50DjABWAXuABcUlS0IIUZmMW7I7L1lamxtZaL25OX3I9TcPN+g3ifl/H2LkfAfrNQlRAg888MC5sLCwYsf8VCUHDhzwnjx5coknMLhyltw9DopnFVF/AjDBQfkKYEUZhiaEEG5zIi2TV37czYz7O/P7X1s59NcqMI8iWZB7XV69jaN6GyvQmY3NeYS3zmQSM1ST1uo2Ro03Jh1/4Gv//OwGnfF28XpMomoZOXLkZdWC2KtXL6eWQMhP9pITQohyMvDjDexOMiYwNRuzggTfe7nOZt7RH6Z2xP63H77VCkwiAiADX3736cL+rQWG3MBrp8DDS5IlIVxEEiYhxOVpyQhjQcjXTpT6Eeezcog9lkrnprVZt/cEfyecIeF0BuvjTpKWaQw+3vNmP654faXdfQoTG3yeK/C8nZMG2xeMSYLUoxDcgoeX7+WLPw7y4Bdb8i7X8LH5L9zzknahEEIUQxImIYR7XTgLMUuh0wOl39oj+kfYvQiS/4XMVBidWHT95J2w3TwL7cI58KtV4le2efVnsnKKX8Ylf7IEcND3Pude4lMDQloD8NrAK/jij4N5l8bf0pZh3ZtB3AI4WSHWAhSiSpPNd4UQ7vVOGPz0jLG1x/hA2Ptzye7XGr4fBnuWwrlDkHkO4sybCowPND6mXPu1jj7raT1e8ADkZFvr7l9T7Ct/jzvpVLLkSOybN5bqPqUUsf+17jY1rHsz46D1TdD9mVI9UwjhPEmYhBDus+XzgmXf/QdWvOz8MxY9WrBs7iCY0dt6/mZtIyH75bWCdQ/+DlOvtJ5/fYfxNX+SBWitCRu93K5bDCCAdLy5yNR7ruSf127g20euJmGS/b5uW17py9ZXr8c345jzv7Z8fKt5kjBpQIFnV2XHjh3ztOw3VqdOnci6det2sJxnZmZWiAFby5Ytq9m7d++Wl1rHVnp6urrqqqva2K4r9eabb9b18fHpdPr06bxBblOnTg1+4IEH7La36NKlS5v169f7A6SkpHjce++9TZs0adIuIiLiii5durRZs2ZNdad/cQ6YTCaGDRvWJDQ0tF3r1q3bbty40eGGzBs2bPBv3bp129DQ0HbDhg1rYjIZP2Q8/vjjjZs1axbRunXrtjfccEOLU6dOeQJs2bLF76677gq7lNhcSRImIYT7rHjRcfmWz6wtPoU5ude4vut747zVjdDvHev1o/8UvGfT1IKb3AKk5htEPT7QmmSZxR5LpdkY+wm7CZMG8O0jV7PT9zHiqj/KrZENqe2j6b71WRgfyIGrFrP+pd4kTBpA3Zq+1KnhA+cLGTN126eF/1ovY/Xr18+1rAZt2RzXcm7ZTqQq+vjjj+vceuutefvlASxcuLB2u3btzn/zzTdO9yEPHTo0LCgoKCchIWF3dHT0njlz5hw8ceLEJQ3H+f777wMPHDjgm5CQsHvatGmJTz31lMP9yJ566qmm06ZNS0xISNh94MAB34ULFwYA3HTTTalxcXHRcXFxMS1btsx87bXX6gN06dLlQnJysve+fftKtMdbeZExTEKI8pOVBj7mTcltk6HRh8DDCyY62Kd0fKB1kUYLreGTLvZlQ82J08pRRcfwRsnHKwGMnTKL0V7bmJRjrJjSobERf/em5h/Wc7Nhaic4sz/vHo9dCwhN/hdG/G19UJI5kbvtE7jyPuvvQ6SjlVgqmMVPN+FEjMPWhFKr2zaD2z9xek0ck8lERETEFdHR0Xs2b97sd80117SNi4vb1apVq+wmTZq0i4mJiTl69KjXgw8+GHbmzBmv4ODgnDlz5iS0atXKbq2hkSNHNkxISPBOTEz0SU5O9n777bcPb968ucaaNWsC6tWrd/G3336L9/Hx0UuWLKk5evToJrm5uURGRmbMmTMn0c/PTy9cuDDgpZdeauLn52fq0qVLuuW5qampHsOHDw+NjY31y8nJUa+88srR++67z26rjuXLl9d44YUXQsHoat20aVNsUFCQXR/vggULgufNm3fAch4dHe2TkZHhOWXKlMSJEyc2ePbZZ08X93sVHR3ts3379uqLFy8+4OlpNEqFh4dnh4eHX9K6S0uWLKk1dOjQ0x4eHvTt2/d8amqqV2JiYrWmTZvmreydmJhYLT093cOySfHQoUNPL168OGjw4MGpd955Z95ed926dTu/cOHCvH3o+vfvf2727NlBb7311vFLidEVpIVJCOF66SeNxODtxgVbjno8D76B4F0dnt0BTXsU/7zf37E/f2R14XXHpxRMuAACndyk+39XcTbtAot8xvOE1098XG0qCb73svSUuVvskM2+4TbJUp5TcXDMvLFu2nFr7KHdjK9B5rFIHvLfsTM8PDzIysryOHPmjMfatWtrREREZPz222814uLivIODg3Nq1qxpevLJJ0OHDh16Oi4uLmbIkCGnn3zyySaOnpWYmOizadOmuB9++CH+iSeeaNanT5/UuLi4GF9fX9OCBQsCMzIy1OOPP95s/vz5++Pi4mJycnJ47733QjIyMtSIESPCli5dGr979+49J06cyJuiOHbs2Aa9e/dO3bVr154NGzbsffXVVxvn389t8uTJ9adOnZoYGxsb8+eff8babiQMkJmZqQ4fPuzTpk2bvMRmzpw5QXfccceZfv36pR88eND38OHDxTZ4/Pvvv75t27bNsG2lKsyAAQOaW7o6bT//+9//gvPXTU5Orma72GWDBg2yExMT7aZpJiYmVmvQoEFeAtW0adPs5OTkAlM5v/rqqzr9+vXL+wd69dVXn9+0aVPNYgN2g2J/F5VS/sALQKjW+lGlVCugjdb68tgSWwhRepYZaO8XMXSj12jrcVAYPLQcLmbCvHthvzkROrEHPu1a8N7wgfCffHt4v3oC3qprHLe9DYC0zIsU+B+4yVXw1CYjibM8q3EU/Dbevt6pOIIm1887vcXTJkFK3Axf3174r81iendo0cd+QHlQmPH1sbXG71NlUIKWIFeKiopK/+2332ps3Lix5ssvv5y8cuXKQK01Xbt2TQfYvn179Z9//nk/wJNPPnnmjTfeaOzoOddff32Kj4+P7tKly4Xc3Fx19913pwJERERcOHjwoPeOHTt8GzdunNWhQ4csgGHDhp3+5JNP6l5//fVpjRs3zmrfvn0WGK0nM2fODAFYt25dwKpVq2pNnTq1PkBWVpaKj4+362Lq2rVr+osvvthk8ODBZ+65556zLVq0sEuYjh075lWzZk27TfEWLVoUvGjRonhPT09uvvnms19//XXQ2LFjTxa2BU5Jt8ZZvnz5geJrla1Ro0bV9/T01E888cQZS1mDBg1yjh8/XiHXyHCmS+5LYBtg/nGIJOB7QBImIUojJxtMF40Wlcrm7SaQlQqvHIdqvo7rbPm88LFJ+T26xvFzqvnC/YusLVGOkiWAW6YULPPygeejwbsG6R41yMnI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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + } + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QI7Rn8viY2eF" + }, + "source": [ + "### `Qini curves with a random curve and with a perfect curve`" + ] + }, + { + "cell_type": "code", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 296 + }, + "id": "plgwP2Srq7ed", + "outputId": "3cc745f4-b95d-4238-89b7-69127b234339" + }, + "source": [ + "fig, ax_roc = plt.subplots(1, 1)\n", + "plot_qini_curve(y_val, uplift_transform_model_val, trmnt_val, name='Transform model', random=True, perfect=True, ax=ax_roc)\n", + "plot_qini_curve(y_val, uplift_two_model, trmnt_val, name='Two models', random=True, perfect=True, ax=ax_roc)" + ], + "execution_count": 17, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "execution_count": 17 + }, + { + "output_type": "display_data", + "data": { + "image/png": "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7ty5MxAAvvrqq4DMzEz9li1bggHAaDSqMzIytElJSdUNxZCXl+dlX38GANXV1bRz587AFStW5AUHB1sHDx5csWnTpoDbbrutrLGi2U0V027I/v37j7Wkv6t0797dXFRU1GzS5UiSqXbCYLQlUz18Zc2UEKLlPJ1MtSd+fn719WUWLVrUc8yYMcYdO3acOHbsmPe4ceP62T/z9vau/8derVZzXV0dhYeHW44cOZLxySefBKxcuTL8gw8+CPnoo49ynL23Xq+/oLaN4z1UKhXsi+LVajUsFkuDIzuNnaNSqWA2my/pcW9mpuXLl5+aPn36BcnhsWPHGkwa9Hq9taampn72atOmTQFGo1E9YMCAJACoqqpSabVa62233VYWGhpqLiwsvOA6FRUV6rCwMMvAgQOrNm/eHOxMjMOGDetXUVGhvrh92bJleVOnTr1gSjEiIqL2119/9e7Tp09dXV0dTCaTOiIiwuzYp1evXheMROXn518wUtWYqqoq0mq1LapRJNN87YR9ZEoWoAshLoUkUw0rLy9XR0VF1QLAG2+8EdZc/8LCQo3FYsGcOXPOL1261HD48OHfrAMbO3asadu2bUFGo1FVXl6u2rZtW/DYsWObXT/UVkJDQy0BAQGWL774wg8A3nrrrdCRI0eawsLCLP7+/pbt27f7AcDq1atD7Odcd911ZStWrAi3T80dOnTIp7y8vNEcYODAgTWOicj69etDXn755VyDwXDYYDAczsnJOfzdd98FGI1G1TXXXGPavn174Llz51QAsGbNmqCEhIRKjUaDG2+80VhbW0svvfRS/c9+7969Onvsjvbv33/M/gCB4+viRAoAJk+efP7tt98OBYB33nkneOTIkUbH9VIAMGbMmIqcnBxtZmamd3V1NW3atClk+vTp55v7+R47dkyblJTUoj9Mkky1EwaTASHaEOi92nT9phCii5BkqmGLFi0qeu6556L69++faDabm+2fk5PjNWrUqH4JCQmJd9xxx2XPP/98/sV9Ro0aVfn73//+7NChQ/sPGzas/x133FHS2IJmV3nnnXd+XbRoUVR8fHzioUOHdMuWLSsAgLfeeivnD3/4Q3RCQkIiM9ePYj3yyCNnEhISqgcOHNg/Li4u6b777otxnPK8WEBAgDU6OrrmyJEjPkajUbV79+5A+3Sj/fOUlBTThg0bAi+//PKq++67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1vTxxx+H9O7du0atViMoKMi8a9euwOuuu84EAEOGDKl48803gwHgjTfeCElJSTE1fcWGJScnVxsMBu8jR474AMDatWtDR48ebRw8eHC1wWDwTk9P9wGADRs2hNjPGTt2bPny5csj7E+uff/997qLr5uenu4zfPjwqsWLFxcNGjSo4siRIxckMeHh4RaLxUKVlZWk3Dfk0UcfLTAYDIcNBsPh06dPHyouLvbKysryHjVqVMX+/fv9Tp06pQGA3bt362tra1V9+vSpTUpKqhk0aFDFwoULe9jjOXbsmPeGDRsCL47ps88+O2lf2O/4ujiRAoApU6acf//990OtViu+/vprX39/f0tDyZSfn5/166+/9rVarXj//fdDb7rppvMAsHHjxoBXXnml+7Zt27L9/f0vSJwyMjJ8+vXr1y5/cztTGuFGh9d1AAYAaIvptHtgG2Gy601EB4jov0Q0WmnrCSDfoU++0gYAEcxcqLwvAhDR2I2I6H4iSiOitJKSkjYI/dLlG5UaU/4yMiWEaHtdfWSqX79+tcxMo0ePNgLAyJEjTf7+/pbw8HALAKxcufLUu+++GxYfH5+4fv360Ndff/2Spif1ej2vXLkyZ8aMGX3i4+MTVSoVHnvssRK9Xs+vvvpq7g033NA3MTGxf1hYWP2U3LJlywrMZjMlJCQk9u3bN+npp5/+zT8E//jHP7rFxcUlxcfHJ3p5efEtt9zymxG1q666quzLL7/0A4DNmzeHzJw584JF7JMmTTq3Zs2akF69epn//ve/502cODEuISEh8ZFHHun13nvv1S84f++993JOnz7tFRMTMyAuLi7pjjvu6O04QnQpZs6cWRYTE1MTExMzYP78+TGvvfZarv2zhISERPv71157LXfevHmxMTExA2JjY2tmzJhRBgALFy6MrqioUI8bNy4+ISEh8fe//33904A7d+4MaOkIo7uQbcCnBSfYJlvTmTnRib6xALba10w5tP8ZQApsNauYiHwA+DHzWWWN1GbYniKMB7CMma9VzhsNYBEz30BE55nZcc/Ac8wcjGakpKRwWlqas99um3vj4Bv49y//xr7Z+6DV/GbUVAghWuXmT29GtH80Xhn3Sptel4j2M3OKY9vBgwdzkpOTz7TpjUSzvvvuO/1LL70UsXnz5l89HYu7VFVV0YgRI/qlpaVlenl5ZtnUwYMHw5KT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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + } + } + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "7vCf0C89Oito" + }, + "source": [ + "" + ], + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/sklift/__init__.py b/sklift/__init__.py index abeeedb..f0ede3d 100644 --- a/sklift/__init__.py +++ b/sklift/__init__.py @@ -1 +1 @@ -__version__ = '0.4.0' +__version__ = '0.4.1' diff --git a/sklift/datasets/datasets.py b/sklift/datasets/datasets.py index 1cc8a1f..ae5c24b 100644 --- a/sklift/datasets/datasets.py +++ b/sklift/datasets/datasets.py @@ -262,7 +262,7 @@ def fetch_x5(data_home=None, dest_subdir=None, download_if_missing=True): :func:`.fetch_megafon`: Load and return the MegaFon Uplift Competition dataset (classification). """ - url_train = 'https://timds.s3.eu-central-1.amazonaws.com/uplift_train.csv.gz' + url_train = 'https://sklift.s3.eu-west-2.amazonaws.com/uplift_train.csv.gz' file_train = url_train.split('/')[-1] csv_train_path = _get_data(data_home=data_home, url=url_train, dest_subdir=dest_subdir, dest_filename=file_train, @@ -277,7 +277,7 @@ def fetch_x5(data_home=None, dest_subdir=None, download_if_missing=True): train = train.drop([target_col, treatment_col], axis=1) - url_clients = 'https://timds.s3.eu-central-1.amazonaws.com/clients.csv.gz' + url_clients = 'https://sklift.s3.eu-west-2.amazonaws.com/clients.csv.gz' file_clients = url_clients.split('/')[-1] csv_clients_path = _get_data(data_home=data_home, url=url_clients, dest_subdir=dest_subdir, dest_filename=file_clients, @@ -285,7 +285,7 @@ def fetch_x5(data_home=None, dest_subdir=None, download_if_missing=True): clients = pd.read_csv(csv_clients_path) clients_features = list(clients.columns) - url_purchases = 'https://timds.s3.eu-central-1.amazonaws.com/purchases.csv.gz' + url_purchases = 'https://sklift.s3.eu-west-2.amazonaws.com/purchases.csv.gz' file_purchases = url_purchases.split('/')[-1] csv_purchases_path = _get_data(data_home=data_home, url=url_purchases, dest_subdir=dest_subdir, dest_filename=file_purchases, diff --git a/sklift/tests/test_datasets.py b/sklift/tests/test_datasets.py index cf38206..a6dc418 100644 --- a/sklift/tests/test_datasets.py +++ b/sklift/tests/test_datasets.py @@ -34,24 +34,23 @@ def test_fetch_lenta(lenta_dataset): assert data.target.shape == lenta_dataset['target.shape'] assert data.treatment.shape == lenta_dataset['treatment.shape'] - -# @pytest.fixture -# def x5_dataset() -> dict: -# data = {'keys': ['data', 'target', 'treatment', 'DESCR', 'feature_names', 'target_name', 'treatment_name'], +#@pytest.fixture +#def x5_dataset() -> dict: +# data = {'keys': ['data', 'target', 'treatment', 'DESCR', 'feature_names', 'target_name', 'treatment_name'], # 'data.keys': ['clients', 'train', 'purchases'], 'clients.shape': (400162, 5), -# 'train.shape': (200039, 1), 'target.shape': (200039,), 'treatment.shape': (200039,)} -# return data -# +# 'train.shape': (200039, 1), 'target.shape': (200039,), 'treatment.shape': (200039,)} +# return data + # -# def test_fetch_x5(x5_dataset): -# data = fetch_x5() -# assert isinstance(data, sklearn.utils.Bunch) -# assert set(data.keys()) == set(x5_dataset['keys']) -# assert set(data.data.keys()) == set(x5_dataset['data.keys']) -# assert data.data.clients.shape == x5_dataset['clients.shape'] -# assert data.data.train.shape == x5_dataset['train.shape'] -# assert data.target.shape == x5_dataset['target.shape'] -# assert data.treatment.shape == x5_dataset['treatment.shape'] +#def test_fetch_x5(x5_dataset): +# data = fetch_x5() +# assert isinstance(data, sklearn.utils.Bunch) +# assert set(data.keys()) == set(x5_dataset['keys']) +# assert set(data.data.keys()) == set(x5_dataset['data.keys']) +# assert data.data.clients.shape == x5_dataset['clients.shape'] +# assert data.data.train.shape == x5_dataset['train.shape'] +# assert data.target.shape == x5_dataset['target.shape'] +# assert data.treatment.shape == x5_dataset['treatment.shape'] @pytest.fixture @@ -85,6 +84,14 @@ def test_fetch_criteo10( assert data.target.shape == target_shape assert data.treatment.shape == treatment_shape +@pytest.mark.parametrize( + 'target_col, treatment_col', + [('visit','new_trmnt'), ('new_target','treatment')] + ) +def test_fetch_criteo_errors(target_col, treatment_col): + with pytest.raises(ValueError): + fetch_criteo(target_col=target_col, treatment_col=treatment_col) + @pytest.fixture def hillstrom_dataset() -> dict: @@ -111,6 +118,10 @@ def test_fetch_hillstrom( assert data.target.shape == target_shape assert data.treatment.shape == hillstrom_dataset['treatment.shape'] +def test_fetch_hillstrom_error(): + with pytest.raises(ValueError): + fetch_hillstrom(target_col='new_target') + @pytest.fixture def megafon_dataset() -> dict: diff --git a/sklift/tests/test_metrics.py b/sklift/tests/test_metrics.py index 4d011bf..47fc4f5 100644 --- a/sklift/tests/test_metrics.py +++ b/sklift/tests/test_metrics.py @@ -7,10 +7,11 @@ from sklearn.utils._testing import assert_array_almost_equal +from ..metrics import make_uplift_scorer from ..metrics import uplift_curve, uplift_auc_score, perfect_uplift_curve from ..metrics import qini_curve, qini_auc_score, perfect_qini_curve from ..metrics import (uplift_at_k, response_rate_by_percentile, - weighted_average_uplift, uplift_by_percentile, treatment_balance_curve) + weighted_average_uplift, uplift_by_percentile, treatment_balance_curve, average_squared_deviation) def make_predictions(binary): @@ -221,6 +222,12 @@ def test_perfect_qini_curve_hard(): assert_array_almost_equal(x_actual, np.array([0., 0., 3.])) assert_array_almost_equal(y_actual, np.array([0.0, 0.0, 0.0])) + +def test_perfect_qini_curve_error(): + y_true, uplift, treatment = make_predictions(binary=True) + with pytest.raises(TypeError): + perfect_qini_curve(y_true, treatment, negative_effect=5) + def test_qini_auc_score(): @@ -255,11 +262,33 @@ def test_qini_auc_score(): treatment = [1, 0, 1] assert_array_almost_equal(qini_auc_score(y_true, uplift, treatment), 0.75) +def test_qini_auc_score_error(): + y_true = [1, 0] + uplift = [0.1, 0.3] + treatment = [0, 1] + with pytest.raises(TypeError): + qini_auc_score(y_true, uplift, treatment, negative_effect=5) + def test_uplift_at_k(): y_true, uplift, treatment = make_predictions(binary=True) assert_array_almost_equal(uplift_at_k(y_true, uplift, treatment, strategy='by_group', k=1), np.array([0.])) + #assert_array_almost_equal(uplift_at_k(y_true, uplift, treatment, strategy='overall', k=2), np.array([0.])) + +@pytest.mark.parametrize( + "strategy, k", + [ + ('new_strategy', 1), + ('by_group', -0.5), + ('by_group', '1'), + ('by_group', 2) + ] +) +def test_uplift_at_k_errors(strategy, k): + y_true, uplift, treatment = make_predictions(binary=True) + with pytest.raises(ValueError): + uplift_at_k(y_true, uplift, treatment, strategy, k) @pytest.mark.parametrize( @@ -277,6 +306,19 @@ def test_response_rate_by_percentile(strategy, group, response_rate): assert_array_almost_equal(response_rate_by_percentile(y_true, uplift, treatment, group, strategy, bins=1), response_rate) +@pytest.mark.parametrize( + "strategy, group, bins", + [ + ('new_strategy', 'control', 1), + ('by_group', 'ctrl', 1), + ('by_group', 'control', 0.5), + ('by_group', 'control', 9999) + ] +) +def test_response_rate_by_percentile_errors(strategy, group, bins): + y_true, uplift, treatment = make_predictions(binary=True) + with pytest.raises(ValueError): + response_rate_by_percentile(y_true, uplift, treatment, group=group, strategy=strategy, bins=bins) @pytest.mark.parametrize( "strategy, weighted_average", @@ -289,7 +331,21 @@ def test_weighted_average_uplift(strategy, weighted_average): y_true, uplift, treatment = make_predictions(binary=True) assert_array_almost_equal(weighted_average_uplift(y_true, uplift, treatment, strategy, bins=1), weighted_average) + +@pytest.mark.parametrize( + "strategy, bins", + [ + ('new_strategy', 1), + ('by_group', 0.5), + ('by_group', 9999) + ] +) +def test_weighted_average_uplift_errors(strategy, bins): + y_true, uplift, treatment = make_predictions(binary=True) + with pytest.raises(ValueError): + weighted_average_uplift(y_true, uplift, treatment, strategy=strategy, bins=bins) + @pytest.mark.parametrize( "strategy, bins, std, total, string_percentiles, data", @@ -307,6 +363,22 @@ def test_uplift_by_percentile(strategy, bins, std, total, string_percentiles, da assert_array_almost_equal( uplift_by_percentile(y_true, uplift, treatment, strategy, bins, std, total, string_percentiles), data) + +@pytest.mark.parametrize( + "strategy, bins, std, total, string_percentiles", + [ + ('new_strategy', 1, True, True, True), + ('by_group', 0.5, True, True, True), + ('by_group', 9999, True, True, True), + ('by_group', 1, 2, True, True), + ('by_group', 1, True, True, 2), + ('by_group', 1, True, 2, True) + ] +) +def test_uplift_by_percentile_errors(strategy, bins, std, total, string_percentiles): + y_true, uplift, treatment = make_predictions(binary=True) + with pytest.raises(ValueError): + uplift_by_percentile(y_true, uplift, treatment, strategy, bins, std, total, string_percentiles) def test_treatment_balance_curve(): @@ -314,4 +386,45 @@ def test_treatment_balance_curve(): idx, balance = treatment_balance_curve(uplift, treatment, winsize=2) assert_array_almost_equal(idx, np.array([1., 100.])) - assert_array_almost_equal(balance, np.array([1., 0.5])) \ No newline at end of file + assert_array_almost_equal(balance, np.array([1., 0.5])) + +@pytest.mark.parametrize( + "strategy", + [ + ('overall'), + ('by_group') + ] +) +def test_average_squared_deviation(strategy): + y_true, uplift, treatment = make_predictions(binary=True) + assert (average_squared_deviation(y_true, uplift, treatment, y_true, uplift, treatment, strategy, bins=1) == 0) + +@pytest.mark.parametrize( + "strategy, bins", + [ + ('new_strategy', 1), + ('by_group', 0.5), + ('by_group', 9999) + ] +) +def test_average_squared_deviation_errors(strategy, bins): + y_true, uplift, treatment = make_predictions(binary=True) + with pytest.raises(ValueError): + average_squared_deviation(y_true, uplift, treatment, y_true, uplift, treatment, strategy=strategy, bins=bins) + +def test_metric_name_error(): + with pytest.raises(ValueError): + make_uplift_scorer('new_scorer', [0, 1]) + +def test_make_scorer_error(): + with pytest.raises(TypeError): + make_uplift_scorer('qini_auc_score', []) + + + + + + + + + \ No newline at end of file diff --git a/sklift/tests/test_models.py b/sklift/tests/test_models.py index 2c9943a..1afa939 100644 --- a/sklift/tests/test_models.py +++ b/sklift/tests/test_models.py @@ -1,4 +1,5 @@ import pytest +import numpy as np from sklearn.linear_model import LogisticRegression, LinearRegression from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler @@ -43,3 +44,50 @@ def test_shape_regression(model, random_xy_dataset_regr): assert model.fit(X, y, treat).predict(X).shape[0] == y.shape[0] pipe = Pipeline(steps=[("scaler", StandardScaler()), ("clf", model)]) assert pipe.fit(X, y, clf__treatment=treat).predict(X).shape[0] == y.shape[0] + +@pytest.mark.parametrize( + "model", + [ + SoloModel(LogisticRegression(), method='dummy'), + SoloModel(LogisticRegression(), method='treatment_interaction'), + ] +) +def test_solomodel_fit_error(model): + X, y, treatment = [[1., 0., 0.],[1., 0., 0.],[1., 0., 0.]], [1., 2., 3.], [0., 1., 0.] + with pytest.raises(TypeError): + model.fit(X, y, treatment) + +@pytest.mark.parametrize( + "model", + [ + SoloModel(LogisticRegression(), method='dummy'), + SoloModel(LogisticRegression(), method='treatment_interaction'), + ] +) +def test_solomodel_pred_error(model): + X_train, y_train, treat_train = (np.array([[5.1, 3.5, 1.4, 0.2], [4.9, 3.0, 1.4, 0.2], [4.7, 3.2, 1.3, 0.2]]), + np.array([0.0, 0.0, 1.0]), np.array([0.0, 1.0, 1.0])) + model.fit(X_train, y_train, treat_train) + with pytest.raises(TypeError): + model.predict(1) + +@pytest.mark.parametrize("method", ['method']) +def test_solomodel_method_error(method): + with pytest.raises(ValueError): + SoloModel(LogisticRegression(), method=method) + +def test_classtransformation_fit_error(): + X, y, treatment = [[1., 0., 0.],[1., 0., 0.],[1., 0., 0.]], [1., 2., 3.], [0., 1., 0.] + with pytest.raises(ValueError): + ClassTransformation(LogisticRegression()).fit(X, y, treatment) + +@pytest.mark.parametrize("method", ['method']) +def test_twomodels_method_error(method): + with pytest.raises(ValueError): + TwoModels(LinearRegression(), LinearRegression(), method=method) + +def test_same_estimator_error(): + est = LinearRegression() + with pytest.raises(ValueError): + TwoModels(est, est) + diff --git a/sklift/tests/test_viz.py b/sklift/tests/test_viz.py index 165deaf..b4b8157 100644 --- a/sklift/tests/test_viz.py +++ b/sklift/tests/test_viz.py @@ -3,7 +3,7 @@ from numpy.testing import assert_allclose -from ..viz import plot_qini_curve, plot_uplift_curve, plot_uplift_preds, plot_uplift_by_percentile +from ..viz import plot_qini_curve, plot_uplift_curve, plot_uplift_preds, plot_uplift_by_percentile, plot_treatment_balance_curve from ..metrics import qini_curve, perfect_qini_curve, uplift_curve, perfect_uplift_curve from ..viz import UpliftCurveDisplay @@ -51,8 +51,6 @@ def test_plot_qini_curve(random, perfect, negative_effect): assert_allclose(viz.x_perfect, x_perfect) assert_allclose(viz.y_perfect, y_perfect) - import matplotlib as mpl - assert isinstance(viz.line_, mpl.lines.Line2D) assert isinstance(viz.ax_, mpl.axes.Axes) assert isinstance(viz.figure_, mpl.figure.Figure) @@ -62,7 +60,8 @@ def test_plot_qini_curve(random, perfect, negative_effect): "qini_auc, estimator_name, expected_label", [ (0.61, None, "plot_qini_curve = 0.61"), - (0.61, "first", "first (plot_qini_curve = 0.61)") + (0.61, "first", "first (plot_qini_curve = 0.61)"), + (None, "None", "None") ] ) def test_default_labels(qini_auc, estimator_name, expected_label): @@ -77,8 +76,6 @@ def test_default_labels(qini_auc, estimator_name, expected_label): assert disp.line_.get_label() == expected_label -from ..viz import plot_uplift_curve -from ..metrics import uplift_curve, perfect_uplift_curve @pytest.mark.parametrize("random", [True, False]) @pytest.mark.parametrize("perfect", [True, False]) @@ -104,8 +101,6 @@ def test_plot_uplift_curve(random, perfect): assert_allclose(viz.x_perfect, x_perfect) assert_allclose(viz.y_perfect, y_perfect) - import matplotlib as mpl - assert isinstance(viz.line_, mpl.lines.Line2D) assert isinstance(viz.ax_, mpl.axes.Axes) assert isinstance(viz.figure_, mpl.figure.Figure) @@ -115,7 +110,8 @@ def test_plot_uplift_curve(random, perfect): "uplift_auc, estimator_name, expected_label", [ (0.75, None, "plot_uplift_curve = 0.75"), - (0.75, "first", "first (plot_uplift_curve = 0.75)") + (0.75, "first", "first (plot_uplift_curve = 0.75)"), + (None, "None", "None") ] ) def test_default_labels(uplift_auc, estimator_name, expected_label): @@ -130,16 +126,19 @@ def test_default_labels(uplift_auc, estimator_name, expected_label): assert disp.line_.get_label() == expected_label + def test_plot_uplift_preds(): trmnt_preds = np.array([1,1,0,1,1,1]) ctrl_preds = np.array([0,1,0,1,0,1]) - + viz = plot_uplift_preds(trmnt_preds, ctrl_preds, log=True, bins=5) - - import matplotlib as mpl + assert isinstance(viz[0], mpl.axes.Axes) assert isinstance(viz[1], mpl.axes.Axes) assert isinstance(viz[2], mpl.axes.Axes) + + with pytest.raises(ValueError): + plot_uplift_preds(trmnt_preds, ctrl_preds, log=True, bins=0) def test_plot_uplift_by_percentile(): y_true, uplift, treatment = make_predictions() @@ -157,8 +156,36 @@ def test_plot_uplift_by_percentile(): assert viz[1].get_title() == "Response rate by percentile" assert isinstance(viz[0], mpl.axes.Axes) assert isinstance(viz[1], mpl.axes.Axes) + viz = plot_uplift_by_percentile(y_true, uplift, treatment, strategy='by_group',kind='bar', bins=1, string_percentiles=True) -def plot_treatment_balance_curve(): + assert viz[0].get_title() == "Uplift by percentile\nweighted average uplift = 0.5000" + assert viz[1].get_xlabel() == "Percentile" + assert viz[1].get_title() == "Response rate by percentile" + assert isinstance(viz[0], mpl.axes.Axes) + assert isinstance(viz[1], mpl.axes.Axes) + + viz = plot_uplift_by_percentile(y_true, uplift, treatment, strategy='by_group',kind='line', bins=1, string_percentiles=False) + assert isinstance(viz, mpl.axes.Axes) + + +@pytest.mark.parametrize( + "strategy, kind, bins, string_percentiles", + [ + ("new_strategy", "bar", 1, False), + ("by_group", "new_bar", 1, False), + ("by_group", "bar", 0, False), + ("by_group", "bar", 100, False), + ("by_group", "bar", 1, 5) + + ] +) +def test_plot_uplift_by_percentile_errors(strategy, kind, bins, string_percentiles): + y_true, uplift, treatment = make_predictions() + with pytest.raises(ValueError): + viz = plot_uplift_by_percentile(y_true, uplift, treatment, strategy=strategy, kind=kind, bins=bins, string_percentiles=string_percentiles) + + +def test_plot_treatment_balance_curve(): y_true, uplift, treatment = make_predictions() viz = plot_treatment_balance_curve(uplift, treatment, winsize=0.5) @@ -166,4 +193,9 @@ def plot_treatment_balance_curve(): assert viz.get_title() == "Treatment balance curve" assert viz.get_xlabel() == "Percentage targeted" assert viz.get_ylabel() == "Balance: treatment / (treatment + control)" - assert isinstance(viz, mpl.axes.Axes) \ No newline at end of file + assert isinstance(viz, mpl.axes.Axes) + +def test_plot_treatment_balance_errors(): + y_true, uplift, treatment = make_predictions() + with pytest.raises(ValueError): + viz = plot_treatment_balance_curve(uplift, treatment, winsize=5) \ No newline at end of file