diff --git a/causalml/dataset/__init__.py b/causalml/dataset/__init__.py index 242b0dbc..f4678b11 100644 --- a/causalml/dataset/__init__.py +++ b/causalml/dataset/__init__.py @@ -5,6 +5,7 @@ from .regression import simulate_unrelated_treatment_control from .regression import simulate_hidden_confounder from .classification import make_uplift_classification +from .classification import make_uplift_classification_logistic from .synthetic import get_synthetic_preds, get_synthetic_preds_holdout from .synthetic import get_synthetic_summary, get_synthetic_summary_holdout diff --git a/causalml/dataset/classification.py b/causalml/dataset/classification.py index db5f3095..0ac0bb93 100644 --- a/causalml/dataset/classification.py +++ b/causalml/dataset/classification.py @@ -1,8 +1,426 @@ +import random import numpy as np import pandas as pd from sklearn.datasets import make_classification +from scipy.optimize import fsolve +#------ Define a list of functions for feature transformation +# @staticmethod +def _f_linear(x): + """ + Linear transformation (actually identical transformation) + """ + return np.array(x) + +# @staticmethod +def _f_quadratic(x): + """ + Quadratic transformation + """ + return np.array(x) * np.array(x) + +# @staticmethod +def _f_cubic(x): + """ + Quadratic transformation + """ + return np.array(x) * np.array(x) * np.array(x) + +# @staticmethod +def _f_relu(x): + """ + Relu transformation + """ + x = np.array(x) + return np.maximum(x, 0) + +# @staticmethod +def _f_sin(x): + """ + Sine transformation + """ + return np.sin(np.array(x)*np.pi) + +# @staticmethod +def _f_cos(x): + """ + Cosine transformation + """ + return np.cos(np.array(x)*np.pi) + +#------ Generating non-linear splines as feature transformation functions +# @staticmethod +def _generate_splines( + n_functions=10, n_initial_points=10, s=0.01, + x_min=-3, x_max=3, y_min=0, y_max=1, + random_seed=2019 + ): + """ + Generate a list of spline functions for feature + transformation. + + Parameters + ---------- + n_functions : int, optional + Number of spline functions to be created. + n_initial_points: int, optional + Number of initial random points to be placed on a 2D plot to fit a spline. + s: float or None, optional + Positive smoothing factor used to choose the number of knots (arg in scipy.interpolate.UnivariateSpline). + x_min: int or float, optional + The minimum value of the X range. + x_max: int or float, optional + The maximum value of the X range. + y_min: int or float, optional + The minimum value of the Y range. + y_max: int or float, optional + The maxium value of the Y range. + random_seed: int, optional + Random seed. + + Returns + ------- + spls: list + List of spline functions. + """ + np.random.seed(random_seed) + spls = [] + for i in range(n_functions): + x = np.linspace(x_min, x_max, n_initial_points) + y = np.random.uniform(y_min,y_max,n_initial_points) + spl = UnivariateSpline(x, y, s=s) + spls.append(spl) + return spls + + +# @staticmethod +def _standardize( x): + """ + Standardize a vector to be mean 0 and std 1. + """ + return (np.array(x) - np.mean(x)) / np.std(x) + +# @staticmethod +def _fixed_transformation(fs, x, f_index=0): + """ + Transform and standardize a vector by a transformation function. + If the given index is within the function list f_index < len(fs), then use fs[f_index] as the transformation function + otherwise, randomly choose a function from the function list. + Parameters + ---------- + fs : list + A collection of functions for transformation. + x : list + Feature values to be transformed. + f_index : int, optional + The function index to be used to select a transformation function. + """ + if f_index 0): + x_name_uplift_transformed = [] + x_name_uplift = [] + for xi in range(n_uplift_dict[treatment_key_i]): + # observed feature + x = np.random.normal(0, 1, df1.shape[0]) + x_name_i = 'x' + str(len(x_name)+1) + '_uplift' + x_name.append(x_name_i) + x_name_uplift.append(x_name_i) + df1[x_name_i] = x + # transformed feature that takes effect in the model + x_name_i = x_name_i + '_transformed' + if random_select_association: + df1[x_name_i] = _fixed_transformation(f_list, x, random.randint(0,len(f_list)-1)) + else: + df1[x_name_i] = _fixed_transformation(f_list, x, xi%len(f_list)) + x_name_uplift_transformed.append(x_name_i) + x_name_uplift_transformed_dict[treatment_key_i] = x_name_uplift_transformed + + # generate mixed informative and uplift features + for treatment_key_i in treatment_name: + if treatment_key_i in n_mix_informative_uplift_dict and n_mix_informative_uplift_dict[treatment_key_i] >0: + for xi in range(n_mix_informative_uplift_dict[treatment_key_i]): + x_name_i = 'x' + str(len(x_name)+1) + '_mix' + x_name.append(x_name_i) + p_weight = np.random.uniform(0, 1) + df1[x_name_i] = (p_weight * df1[np.random.choice(x_informative_name)] + + (1-p_weight) * df1[np.random.choice(x_name_uplift)]) + + # generate conversion probability ------------------------------------------------# + # baseline conversion + coef_classify = [] + for ci in range(n_classification_informative): + rcoef = [0] + while np.abs(rcoef) < 0.1: + rcoef = np.random.randn(1) * np.sqrt(1./n_classification_informative) + coef_classify.append(rcoef[0]) + x_classify = df1[x_informative_transformed].values + p1 = positive_class_proportion + a10 = np.log(p1/(1.-p1)) + err = np.random.normal(0, error_std, df1.shape[0]) + xb_array = (x_classify * coef_classify).sum(axis=1) + err + # solve for the constant value so that the output metric mean equal to the function input positive_class_proportion + a1 = fsolve(_softmax,a10,args=(p1,xb_array))[0] + df1['conversion_prob_linear'] = a1 + xb_array + df1['control_conversion_prob_linear'] = df1['conversion_prob_linear'].values + + # uplift conversion + for treatment_key_i in treatment_name: + if treatment_key_i in delta_uplift_dict and np.abs(delta_uplift_dict[treatment_key_i]) > 0.: + treatment_index = ( + df1.index[df1['treatment_group_key'] == treatment_key_i].tolist() + ) + # coefficient + coef_uplift = [] + for ci in range(n_uplift_dict[treatment_key_i]): + #rcoef = [0] + #while np.abs(rcoef) < 0.1: + # rcoef = np.random.uniform(-1, 1, 1) + rcoef = [0.5] + coef_uplift.append(rcoef[0]) + x_uplift = df1.loc[:,x_name_uplift_transformed_dict[treatment_key_i]].values + p2 = mean_dict[treatment_key_i] + a20 = np.log(p2/(1.- p2)) - a1 + xb_array = df1['conversion_prob_linear'].values + (x_uplift * coef_uplift).sum(axis=1) + xb_array_treatment = xb_array[treatment_index] + a2 = fsolve(_softmax,a20,args=(p2,xb_array_treatment))[0] + df1['%s_conversion_prob_linear'%(treatment_key_i)] = a2 + xb_array + df1.loc[treatment_index,'conversion_prob_linear'] = df1.loc[treatment_index,'%s_conversion_prob_linear'%(treatment_key_i)].values + else: + df1['%s_conversion_prob_linear'%(treatment_key_i)] = df1['conversion_prob_linear'].values + + + + + # generate conversion probability and true treatment effect ---------------------------------# + df1['conversion_prob'] = 1 / (1 + np.exp(- df1['conversion_prob_linear'].values)) + df1['control_conversion_prob'] = 1 / (1 + np.exp(- df1['control_conversion_prob_linear'].values)) + for treatment_key_i in treatment_name: + df1['%s_conversion_prob'%(treatment_key_i)] = 1 / (1 + np.exp(- df1['%s_conversion_prob_linear'%(treatment_key_i)].values)) + df1['%s_true_effect'%(treatment_key_i)] = df1['%s_conversion_prob'%(treatment_key_i)].values - df1['control_conversion_prob'].values + + # generate Y ------------------------------------------------------------# + df1['conversion_prob'] = [max(0, min(1, xi)) + for xi in df1['conversion_prob'].values] + Y1 = np.random.binomial(1, df1['conversion_prob'].values) + + df1[y_name] = Y1 + + return df1, x_name + + +# ------ Data generation function (V1) using make_classification from sklearn def make_uplift_classification(n_samples=1000, treatment_name=['control', 'treatment1', 'treatment2', 'treatment3'], y_name='conversion', @@ -181,3 +599,8 @@ def make_uplift_classification(n_samples=1000, df_res[y_name] = Y df_res['treatment_effect'] = Y - Y1 return df_res, x_name + + + + + diff --git a/examples/logistic_regression_based_data_generation_for_uplift_classification.ipynb b/examples/logistic_regression_based_data_generation_for_uplift_classification.ipynb new file mode 100644 index 00000000..df668dd0 --- /dev/null +++ b/examples/logistic_regression_based_data_generation_for_uplift_classification.ipynb @@ -0,0 +1,518 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Logistic Regression Based Data Generation Function for Uplift Classification Problem\n", + "This Data Generation Function uses Logistic Regression as the underlying data generation model.\n", + "This function enables better control of feature patterns: how feature is associated with outcome baseline and treatment effect. It enables 6 differernt patterns: Linear, Quadratic, Cubic, Relu, Sine, and Cosine. \n", + "\n", + "This notebook shows how to use this data generation function to generate data, with a visualization of the feature patterns.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "import numpy as np\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Import Data Generation Function" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "The sklearn.utils.testing module is deprecated in version 0.22 and will be removed in version 0.24. The corresponding classes / functions should instead be imported from sklearn.utils. Anything that cannot be imported from sklearn.utils is now part of the private API.\n" + ] + } + ], + "source": [ + "from causalml.dataset import make_uplift_classification_logistic" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Generate Data" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [], + "source": [ + "df, feature_name = make_uplift_classification_logistic( n_samples=100000,\n", + " treatment_name=['control', 'treatment1', 'treatment2', 'treatment3'],\n", + " y_name='conversion',\n", + " n_classification_features=10,\n", + " n_classification_informative=5,\n", + " n_classification_redundant=0,\n", + " n_classification_repeated=0,\n", + " n_uplift_dict={'treatment1': 2, 'treatment2': 2, 'treatment3': 3},\n", + " n_mix_informative_uplift_dict={'treatment1': 1, 'treatment2': 1, 'treatment3': 0},\n", + " delta_uplift_dict={'treatment1': 0.05, 'treatment2': 0.02, 'treatment3': -0.05},\n", + " feature_association_list = ['linear','quadratic','cubic','relu','sin','cos'],\n", + " random_select_association = False,\n", + " random_seed=20200416\n", + " \n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
treatment_group_keyx1_informativex1_informative_transformedx2_informativex2_informative_transformedx3_informativex3_informative_transformedx4_informativex4_informative_transformedx5_informative...conversion_probcontrol_conversion_probcontrol_true_effecttreatment1_conversion_probtreatment1_true_effecttreatment2_conversion_probtreatment2_true_effecttreatment3_conversion_probtreatment3_true_effectconversion
0treatment1-0.194205-0.1920431.7914081.5726090.6780280.080696-0.169306-0.683035-1.837155...0.1267700.0761380.00.1267700.0506320.0875450.0114070.029396-0.0467420
1treatment1-0.898070-0.8944620.252125-0.663393-0.842844-0.156004-0.047769-0.683035-0.251752...0.0642780.0707990.00.064278-0.0065220.1010760.0302770.050778-0.0200210
2treatment10.7010020.7013250.239320-0.6678671.7007661.278676-0.734568-0.683035-1.130113...0.0184800.0149470.00.0184800.0035340.0180550.0031090.0193270.0043800
3control-1.653684-1.648524-0.119123-0.698492-0.037645-0.0003550.6874290.495943-1.427400...0.1027990.1027990.00.101410-0.0013900.040230-0.0625690.030753-0.0720460
4treatment31.0579091.057498-2.0195232.190564-0.950180-0.223370-1.505741-0.683035-0.399457...0.0129640.1062410.00.1713090.0650680.1145260.0082850.012964-0.0932770
\n", + "

5 rows × 47 columns

\n", + "
" + ], + "text/plain": [ + " treatment_group_key x1_informative x1_informative_transformed \\\n", + "0 treatment1 -0.194205 -0.192043 \n", + "1 treatment1 -0.898070 -0.894462 \n", + "2 treatment1 0.701002 0.701325 \n", + "3 control -1.653684 -1.648524 \n", + "4 treatment3 1.057909 1.057498 \n", + "\n", + " x2_informative x2_informative_transformed x3_informative \\\n", + "0 1.791408 1.572609 0.678028 \n", + "1 0.252125 -0.663393 -0.842844 \n", + "2 0.239320 -0.667867 1.700766 \n", + "3 -0.119123 -0.698492 -0.037645 \n", + "4 -2.019523 2.190564 -0.950180 \n", + "\n", + " x3_informative_transformed x4_informative x4_informative_transformed \\\n", + "0 0.080696 -0.169306 -0.683035 \n", + "1 -0.156004 -0.047769 -0.683035 \n", + "2 1.278676 -0.734568 -0.683035 \n", + "3 -0.000355 0.687429 0.495943 \n", + "4 -0.223370 -1.505741 -0.683035 \n", + "\n", + " x5_informative ... conversion_prob control_conversion_prob \\\n", + "0 -1.837155 ... 0.126770 0.076138 \n", + "1 -0.251752 ... 0.064278 0.070799 \n", + "2 -1.130113 ... 0.018480 0.014947 \n", + "3 -1.427400 ... 0.102799 0.102799 \n", + "4 -0.399457 ... 0.012964 0.106241 \n", + "\n", + " control_true_effect treatment1_conversion_prob treatment1_true_effect \\\n", + "0 0.0 0.126770 0.050632 \n", + "1 0.0 0.064278 -0.006522 \n", + "2 0.0 0.018480 0.003534 \n", + "3 0.0 0.101410 -0.001390 \n", + "4 0.0 0.171309 0.065068 \n", + "\n", + " treatment2_conversion_prob treatment2_true_effect \\\n", + "0 0.087545 0.011407 \n", + "1 0.101076 0.030277 \n", + "2 0.018055 0.003109 \n", + "3 0.040230 -0.062569 \n", + "4 0.114526 0.008285 \n", + "\n", + " treatment3_conversion_prob treatment3_true_effect conversion \n", + "0 0.029396 -0.046742 0 \n", + "1 0.050778 -0.020021 0 \n", + "2 0.019327 0.004380 0 \n", + "3 0.030753 -0.072046 0 \n", + "4 0.012964 -0.093277 0 \n", + "\n", + "[5 rows x 47 columns]" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "['x1_informative', 'x2_informative', 'x3_informative', 'x4_informative', 'x5_informative', 'x6_irrelevant', 'x7_irrelevant', 'x8_irrelevant', 'x9_irrelevant', 'x10_irrelevant', 'x11_uplift', 'x12_uplift', 'x13_uplift', 'x14_uplift', 'x15_uplift', 'x16_uplift', 'x17_uplift', 'x18_mix', 'x19_mix']" + ], + "text/plain": [ + "['x1_informative',\n", + " 'x2_informative',\n", + " 'x3_informative',\n", + " 'x4_informative',\n", + " 'x5_informative',\n", + " 'x6_irrelevant',\n", + " 'x7_irrelevant',\n", + " 'x8_irrelevant',\n", + " 'x9_irrelevant',\n", + " 'x10_irrelevant',\n", + " 'x11_uplift',\n", + " 'x12_uplift',\n", + " 'x13_uplift',\n", + " 'x14_uplift',\n", + " 'x15_uplift',\n", + " 'x16_uplift',\n", + " 'x17_uplift',\n", + " 'x18_mix',\n", + " 'x19_mix']" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "feature_name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Experiment Group Mean" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "treatment_group_key\n", + "control 0.09896\n", + "treatment1 0.15088\n", + "treatment2 0.12042\n", + "treatment3 0.04972\n", + "Name: conversion, dtype: float64" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.groupby(['treatment_group_key'])['conversion'].mean()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Visualize Feature Pattern" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "treatment_group_key\n", + "control 0.09896\n", + "treatment1 0.15088\n", + "Name: conversion, dtype: float64" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Extract control and treatment1 for illustration\n", + "treatment_group_keys = ['control','treatment1']\n", + "y_name='conversion'\n", + "df1 = df[df['treatment_group_key'].isin(treatment_group_keys)].reset_index(drop=True)\n", + "df1.groupby(['treatment_group_key'])['conversion'].mean()" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABSgAAADnCAYAAAAdF7hOAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nOzde1yUZd4/8A+g6GolijhYirpKiinSysE8kZqV5ob5vPBUarZsZHba1MKeyg4qGmVbq6lFtI92kqcsXA9Uu7LioTxUZpnbz3JN2BJZlSwTTOT3hw+zM8w9M9d9z3Uf5/N+vXwVw/C97oH5fu/r+s59iKipqWkAERERERERERERkQkizd4AIiIiIiIiIiIiCl9sUBIREREREREREZFp2KAkIiIiIiIiIiIi07BBSURERERERERERKZhg5KIiIiIiIiIiIhMwwYlERERERERERERmYYNSiIiIiIiIiIiIjKNKQ3KwsJCJCcnw+VyITMzEzt27PD73G3btuHaa69Ft27dEB8fj7S0NPzpT3/yeV5JSQkyMjLQoUMHZGRk4C9/+YueL4GISDrWRiIiX6yNRES+WBuJyGkMb1CuXbsWeXl5mDVrFsrLy5Geno7s7GxUVFQoPv+iiy5Cbm4uNm7ciI8++gizZ89Gfn4+CgsL3c/ZtWsXbrvtNmRnZ2Pr1q3Izs7Grbfeij179hj1soiIQsLaSETki7WRiMgXayMROVFETU1Ng5EDjhgxAldccQWef/5592O/+c1vkJWVhXnz5gnFuOWWW9CiRQu8/PLLAIDp06fj5MmTePfdd93PycrKQvv27d3PISKyMtZGIiJfrI1ERL5YG4nIiQw9gvLs2bPYu3cvhg8f7vX48OHDsXPnTqEYn332GXbt2oVBgwa5H9u9e7dPzBEjRgjHJCIyE2sjEZEv1kYiIl+sjUTkVM2MHOz48eOor69HXFyc1+NxcXE4duxYwJ/t3bs3/v3vf+PcuXN48MEHcdttt7m/V1VVpSkmEZEVsDYSEflibSQi8sXaSEROZWiDMhQbN27E6dOnsWfPHsybNw9dunTBxIkTzd4sIiJTsTYSEflibSQi8sXaSERWZugp3rGxsYiKikJ1dbXX49XV1ejQoUPAn+3atSuuuOIKTJs2DTNnzsSiRYvc33O5XJpiGungwYMcg2NwDIePoRVrI8fgGBzDyWNoxdrIMTgGx3DyGFqFa210yt+dY3AMjuGfoQ3K6OhopKSkoKyszOvxsrIyZGRkCMc5f/48zp496/46LS0t5JhERGZhbSQi8sXaSETki7WRiJzK8FO8Z86cidzcXPTv3x8ZGRkoKirC0aNHMX36dABAbm4uAGDlypXu/3bp0gWJiYkAgO3bt2Pp0qX43e9+5455xx13YPTo0Xj22Wdxww03YP369di6dStKS0sNfnVERNqwNhIR+WJtJCLyxdpIRE5keINy3LhxOHHiBAoKClBVVYWkpCQUFxcjISEBAFBZWen1/Pr6ejz22GM4cuQImjVrhq5du2LevHleF/RtLMrz58/HwoUL0a1bNxQVFSE1NdXQ10ZEpBVrIxGRL9ZGIiJfrI1E5ESm3CQnJycHOTk5it/bsGGD19d33nkn7rzzzqAxs7KykJWVJWX7iIjMwNpIROSLtZGIyBdrIxE5jaHXoCQiIiIiIiIiIiLyZMoRlHZw7tw5nD59Wlq8li1b4ocffpAWj2NYf4zo6GicPn0arVq1QkREhK5jERERERERERHZFRuUChoaGvDjjz+iTZs2iIyUc5BpixYt0LJlSymxOIY9xoiOjkZUVBRqamoQExPDJiURERERERERkQKe4q3g9OnTuOiii6Q1Jyk8RUREIDo6Gq1bt8bPP/9s9uYQEREREREREVkSO3AK6uvr0bx5c7M3gxyiefPmOHfunNmbQURERERERERkSWxQEumMp3YTEREREREREfnHBiURERERERERERGZhg1KIiIiIiIiIiIiMg0blKSLF154AevWrdMldkxMDPLz83WJTURERERERERExmpm9gbYyZQXyzX/7PmG84iMCK0fvPr2oSH9vJGWL1+Oq666CjfeeKPZm0JERERERERERBbGIyjJdHV1dWZvAhERERERERERmYQNyjDy+eef4+abb0a3bt0QHx+P1NRULFmyBADQ0NCAZcuWITU1FXFxcejZsyfmzJmDU6dOecWIj4/H/PnzsWLFCiQnJ6NTp04YPXo0Dhw44H5O3759UVFRgeLiYsTExCAmJgYzZswAAOTn5yMmJgZffvklxo0bh8suuwy33nqr1zYMGjQo4DYQEREREREREZFz8BTvMPHxxx9jzJgx6NatGxYuXIhLL70Uhw4dwv79+wEATz75JJYs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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "color_dict = {'control':'#2471a3','treatment1':'#FF5733','treatment2':'#5D6D7E'\n", + " ,'treatment3':'#34495E','treatment4':'#283747'}\n", + "\n", + "hatch_dict = {'control':'','treatment1':'//'}\n", + "\n", + "x_name_plot = ['x11_uplift', 'x12_uplift', 'x2_informative', 'x5_informative']\n", + "\n", + "x_new_name_plot = ['Uplift Feature 1', 'Uplift Feature 2', 'Classification Feature 1','Classification Feature 2']\n", + "opacity = 0.8\n", + "\n", + "plt.figure(figsize=(20, 3))\n", + "subplot_list = [141,142,143,144]\n", + "counter = 0\n", + "bar_width = 0.9/len(treatment_group_keys)\n", + "for x_name_i in x_name_plot:\n", + " bins = np.percentile(df1[x_name_i].values, np.linspace(0, 100, 11))[:-1]\n", + " df1['x_bin'] = np.digitize(df1[x_name_i].values, bins)\n", + " df_gb = df1.groupby(['treatment_group_key','x_bin'],as_index=False)[y_name].mean()\n", + " plt.subplot(subplot_list[counter])\n", + " for ti in range(len(treatment_group_keys)):\n", + " x_index = [ti * bar_width - len(treatment_group_keys)/2*bar_width + xi for xi in range(10)]\n", + " plt.bar(x_index, \n", + " df_gb[df_gb['treatment_group_key']==treatment_group_keys[ti]][y_name].values, \n", + " bar_width,\n", + " alpha=opacity,\n", + " color=color_dict[treatment_group_keys[ti]],\n", + " hatch = hatch_dict[treatment_group_keys[ti]],\n", + " label=treatment_group_keys[ti]\n", + " )\n", + " plt.xticks(range(10), [int(xi+10) for xi in np.linspace(0, 100, 11)[:-1]])\n", + " plt.xlabel(x_new_name_plot[counter],fontsize=16)\n", + " plt.ylabel('Conversion',fontsize=16)\n", + " #plt.title(x_name_i)\n", + " if counter == 0:\n", + " plt.legend(treatment_group_keys, loc=2,fontsize=16)\n", + " plt.ylim([0.,0.3])\n", + " counter+=1\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the figure above, Uplift Feature 1 has a linear pattern on treatment effect, Uplift Feature 2 has a quadratic pattern on treatment effect, Classification Feature 1 has a quadratic pattern on baseline for both treatment and control, and Classification Feature 2 has a Sine pattern on baseline for both treatment and control." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}