{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "# The 2nd place solution of the [RetailHero Uplift Modelling contest ](https://retailhero.ai/c/uplift_modeling/overview) \n", "\n", "### To open Notebook for read, use [nbviewer](https://nbviewer.jupyter.org/github/kirrlix1994/Retail_hero/blob/master/Retail_hero_contest_2nd_place_solution.ipynb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary of the solution:\n", "###### Main points to get good results in this competition:\n", "-\tUse few features, pre-select features. My best submission used only 6 ones!\n", "\n", "\n", "-\tMake NOT very complex estimators for fitting. I used mainly different gradient boosting realizations (Catboost / Xgboost / Lightgbm), best results gave models with trees of death 1-2.\n", "\n", "\n", "-\tUse Class transformation approach for uplift modelling.\n", "\n", "\n", "- Try to make more accurate local validation and do not rely only on public validation score. For testing hypotheses I used to make N (N = 30, 50) train - test splits and calculate test scores mean and standard deviation for making decisions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Additional info:\n", " \n", " Package with different uplift model realizations: \n", " [uplift modelling package](https://github.com/maks-sh/scikit-uplift/)\n", "\n", " Tutorial about uplift and approaches (in Russian): \n", " [uplift modeling approaches article](https://habr.com/ru/company/ru_mts/blog/485980/)\n", " \n", " Additional code with my feature engenearing, experimemts and validation: \n", " [retail hero research](/research)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### code is on py37, requirements:\n", "- numpy==1.16.1\n", "- pandas==0.24.1\n", "- scikit-learn==0.21.3\n", "- scikit-uplift==0.0.3\n", "- xgboost==0.90\n", "- matplotlib==3.1.1" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import gc\n", "import pandas as pd\n", "import numpy as np\n", "from datetime import datetime\n", "\n", "from xgboost import XGBClassifier\n", "from sklift.models import ClassTransformation\n", "\n", "from sklift.metrics import uplift_at_k\n", "import matplotlib.pyplot as plt\n", "\n", "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### LOAD INITIAL DATA" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": true }, "outputs": [], "source": [ "df_clients = pd.read_csv(\n", " 'data/clients.csv', \n", " index_col='client_id', \n", " parse_dates=['first_issue_date', 'first_redeem_date']\n", ")\n", "\n", "df_purchases = pd.read_csv(\n", " 'data/purchases.csv'\n", " index_col='client_id', \n", " parse_dates=['transaction_datetime']\n", ")\n", "\n", "df_dtrain = pd.read_csv('data/uplift_train.csv', index_col='client_id')\n", "df_test = pd.read_csv('data/uplift_test.csv', index_col='client_id')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### MAKE FEATURES FOR TRAIN AND TEST" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "###### Final second place submission used only 6 features: " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "'first_redeem_date' - make date as an integer feature" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": true }, "outputs": [], "source": [ "df_clients['first_redeem_date'] =\\\n", " df_clients['first_redeem_date']\\\n", " .fillna(datetime(2019, 3, 19, 0, 0))\n", "\n", "df_clients.loc[:, 'first_redeem_date'] =\\\n", " ((df_clients['first_redeem_date'] - pd.Timestamp(\"1970-01-01\")) // pd.Timedelta('1d'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Aggregate df_purchases data" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# two -level aggregation: \n", "\n", "# 1. aggregate to (client, transaction) take one row only \n", "# ('express_points_spent', 'purchase_sum' - same for one transaction)\n", "\n", "# 2. aggregate all transactions to client.\n", "\n", "\n", "df_purch = df_purchases\\\n", " .groupby(['client_id','transaction_id'])[['express_points_spent', 'purchase_sum']]\\\n", " .last()\\\n", " .groupby('client_id')\\\n", " .agg({\n", " 'express_points_spent': ['mean', 'sum'], \n", " 'purchase_sum': ['sum']\n", " })\n", " \n", "# set readable column names:\n", "df_purch.columns =\\\n", " ['express_spent_mean', 'express_points_spent_sum', 'purchase_sum__sum']" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ "#'regular_points_received_sum_last_m'\n", "\n", "reg_points_last_m = df_purchases[\n", " df_purchases['transaction_datetime'] > '2019-02-18'\n", " ]\\\n", " .groupby(['client_id', 'transaction_id'])['regular_points_received']\\\n", " .last()\\\n", " .groupby('client_id')\\\n", " .sum()\n", " \n", "reg_points_last_m = pd.DataFrame({\n", " 'regular_points_received_sum_last_m': reg_points_last_m \n", "})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Make 'transaction_datetime' from purchases data frame as integer. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Join clients df and purchases df and calculate difference between 'transaction_datetime' and ''first_redeem_date' (date_diff)." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "df_purchases.loc[:,'purch_day'] =\\\n", " ((df_purchases['transaction_datetime'] - pd.Timestamp(\"1970-01-01\")) // pd.Timedelta('1d'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calculate features from purchases data for all transactions after redeem date:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# 'after_redeem_sum'\n", "\n", "df_purch_joined = pd.merge(\n", " df_purchases[\n", " ['client_id', 'purch_day', 'transaction_id', 'purchase_sum']\n", " ],\n", " df_clients\\\n", " .reset_index()[\n", " ['client_id', 'first_redeem_date']\n", " ], on='client_id', how='left')\n", "\n", "df_purch_joined = df_purch_joined\\\n", " .assign(date_diff=\\\n", " df_purch_joined['first_redeem_date'] - df_purch_joined['purch_day']\n", " )\n", "\n", "df_purch_agg = df_purch_joined[\n", " df_purch_joined['date_diff'] <= 0\n", " ]\\\n", " .groupby(\n", " ['client_id', 'transaction_id']\n", " )\\\n", " .last()\\\n", " .groupby('client_id')['purchase_sum']\\\n", " .sum()\n", " \n", "after_redeem_sum = pd.DataFrame(data={\n", " 'after_redeem_sum': df_purch_agg\n", "})\n", "\n", "del df_purch_joined, df_purch_agg\n", "gc.collect();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "'purch_delta' - difference in days between last and first transaction " ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "df_purch_delta_agg = df_purchases\\\n", " .groupby('client_id')\\\n", " .agg({\n", " 'purch_day': ['max', 'min']\n", " })\n", "\n", "df_purch_delta = pd.DataFrame(\n", " data=df_purch_delta_agg['purch_day']['max'] -\\\n", " df_purch_delta_agg['purch_day']['min'] + 1,\n", " columns=['purch_delta']\n", ")\n", "\n", "del df_purch_delta_agg\n", "gc.collect();" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "------" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Concat all data together:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": true }, "outputs": [], "source": [ "df_feats = pd.concat([\n", " df_clients[['first_redeem_date']], \n", " df_purch, \n", " df_purch_delta, \n", " reg_points_last_m, \n", " after_redeem_sum\n", "], axis=1, sort=False)\n", "\n", "df_feats = df_feats\\\n", " .assign(\n", " avg_spent_perday=\\\n", " df_feats['purchase_sum__sum'] / df_feats['purch_delta'],\n", " after_redeem_sum_perday =\\\n", " df_feats['after_redeem_sum'] / df_feats['purch_delta']\n", " )\\\n", " .drop([\n", " 'purch_delta', 'purchase_sum__sum', 'after_redeem_sum'\n", " ], axis=1\n", " )" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(400162, 6)\n" ] }, { "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", "
first_redeem_dateexpress_spent_meanexpress_points_spent_sumregular_points_received_sum_last_mavg_spent_perdayafter_redeem_sum_perday
000012768d175350.00.010.026.95192326.951923
000036f903172790.00.013.789.13636489.136364
\n", "
" ], "text/plain": [ " first_redeem_date express_spent_mean express_points_spent_sum \\\n", "000012768d 17535 0.0 0.0 \n", "000036f903 17279 0.0 0.0 \n", "\n", " regular_points_received_sum_last_m avg_spent_perday \\\n", "000012768d 10.0 26.951923 \n", "000036f903 13.7 89.136364 \n", "\n", " after_redeem_sum_perday \n", "000012768d 26.951923 \n", "000036f903 89.136364 " ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# train and test features\n", "print(df_feats.shape)\n", "df_feats.head(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Make train and test data: join clints ids and treatment and target for train." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Train df shape: (200039, 8)\n", "Test df shape: (200123, 6)\n" ] } ], "source": [ "# train data:\n", "df_train_feats = df_train\\\n", " .join(\n", " df_feats, \n", " how='left'\n", " )\n", " \n", "df_test_feats = df_test\\\n", " .join(\n", " df_feats, \n", " how='left'\n", " )\n", " \n", "print(f'Train df shape: {df_train_feats.shape}')\n", "print(f'Test df shape: {df_test_feats.shape}')" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# save final train / test data \n", "df_train_feats.to_csv('data/retail_hero_final_model_train_data.csv')\n", "df_test_feats.to_csv('data/retail_hero_final_model_test_data.csv')" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "-----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### SET MODEL\n", "Use uplift class tranformation approach for uplift prediction with XGBoost as an estimator." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": true }, "outputs": [], "source": [ "xgb_est_params = {\n", " 'max_depth':2,\n", " 'learning_rate': 0.2, \n", " 'n_estimators': 100,\n", " 'nthread':40,\n", " 'n_gpus':0,\n", " 'seed':42\n", "}\n", "\n", "estimator = XGBClassifier(\n", " **xgb_est_params\n", ")\n", "\n", "uplift_model_cl_tr = ClassTransformation(\n", " estimator=estimator\n", ")" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "-----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### FIT MODEL ON ALL TRAIN DATA" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "scrolled": true }, "outputs": [], "source": [ "uplift_model_cl_tr.fit(\n", " X=df_train_feats\\\n", " .drop(\n", " ['treatment_flg', 'target'], \n", " axis=1\n", " ),\n", " y=df_train_feats['target'],\n", " treatment=df_train_feats['treatment_flg']\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "--------" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Make predictions on whole train and test sets.\n", "\n", "#### Calculate uplift@30% metric on train data.\n", "\n", "###### **NOTE: In this contest uplift@30% metric calculates as follows: \n", "All test data are sorted in descending order by 'predicted uplift'. Then calculates target share / conversion in top 30% of treatment group and conversion in top 30% of control group SEPARATELY. Metric is then the difference between two conversions.\n", "
\n", "\n", " Usually uplift@30% metric calculates differently. Firstly selects top 30% of ALL test data and only then calculates conversion in treatment and control group and they are subtracted." ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# predicts\n", "uplift_tr = uplift_model_cl_tr.predict(\n", " df_train_feats\\\n", " .drop(['treatment_flg', 'target'], axis=1),\n", ")\n", "\n", "uplift_ts = uplift_model_cl_tr.predict(\n", " df_test_feats\n", ")" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Uplift@30% on train data: 0.105\n" ] } ], "source": [ "# score on train:\n", "df_train_scores = df_train_feats[['treatment_flg', 'target']]\\\n", " .assign(uplift_score=uplift_tr)\n", " \n", "train_score = uplift_at_k(\n", " y_true=df_train_scores['target'],\n", " uplift=df_train_scores['uplift_score'],\n", " treatment=df_train_scores['treatment_flg']\n", ")\n", "\n", "print(f'Uplift@30% on train data: {train_score:.3f}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Make submit:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Submit data shape: (200123, 1)\n", "\n", "client_id,uplift\n", "000048b7a6,0.03721845\n", "000073194a,0.019023776\n", "00007c7133,0.032182574\n", "00007f9014,0.016914487\n" ] } ], "source": [ "df_submit = df_test_feats\\\n", " .assign(uplift=uplift_ts)[['uplift']]\n", "\n", "print(f'Submit data shape: {df_submit.shape}\\n')\n", "df_submit.head(2)\n", "\n", "df_submit.to_csv('submissions/retail_hero_2nd_place_submit.csv')\n", "\n", "!head -5 submissions/retail_hero_2nd_place_submit.csv" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "-----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "------" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### FEATURE IMPORTANCE" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is the area of research, how to calculate feature importance in uplift models. \n", "\n", "Here feature importance is just vanilla information gain in XGBoost estimator, used in Class transformation approach.\n" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "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", "
featurevalue
4first_redeem_date64.531791
2express_points_spent_sum14.171003
3express_spent_mean14.151961
5regular_points_received_sum_last_m7.514503
1avg_spent_perday5.645311
0after_redeem_sum_perday4.776374
\n", "
" ], "text/plain": [ " feature value\n", "4 first_redeem_date 64.531791\n", "2 express_points_spent_sum 14.171003\n", "3 express_spent_mean 14.151961\n", "5 regular_points_received_sum_last_m 7.514503 \n", "1 avg_spent_perday 5.645311 \n", "0 after_redeem_sum_perday 4.776374 " ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_feat_imp = pd.DataFrame([\n", " uplift_model_cl_tr\\\n", " .estimator\\\n", " .get_booster()\\\n", " .get_score(importance_type='gain')\n", " ]\n", ").T.reset_index()\n", "\n", "df_feat_imp.columns =\\\n", " [\"feature\", \"value\"]\n", " \n", "df_feat_imp\\\n", " .sort_values('value', ascending=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "------" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### PLOT ULIFT PREDICTIONS FOR TRAIN / TEST DATA" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(20, 8));\n", "\n", "plt.hist(\n", " df_train_scores['uplift_score'],\n", " bins=200, \n", " color='red', \n", ");\n", "\n", "plt.xlim(-0.2, 0.75);\n", "plt.title('Uplift predictions on train data', size=15);\n", "\n", "\n", "plt.figure(figsize=(20, 8));\n", "\n", "plt.hist(\n", " df_submit['uplift'],\n", " bins=200, \n", " color='blue', \n", ");\n", "\n", "plt.xlim(-0.2, 0.75);\n", "plt.title('Uplift predictions on test data', size=15);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Looks quite similar." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.6.3" } }, "nbformat": 4, "nbformat_minor": 2 }