<jupyter_start><jupyter_text>0.0. Imports<jupyter_code>import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

from IPython.display import HTML
from IPython.display import Image
from geopy.geocoders import Nominatim

from sklearn import preprocessing as pp
from sklearn import model_selection as ms
from sklearn import dummy
from sklearn import metrics
from sklearn import neighbors
from sklearn import svm
from sklearn import ensemble
from sklearn import linear_model<jupyter_output><empty_output><jupyter_text>0.1. Helper Functions<jupyter_code>def jupyter_settings():
    %matplotlib inline
    %pylab inline
    
    plt.style.use( 'ggplot')
    plt.rcParams['figure.figsize'] = [24, 9]
    plt.rcParams['font.size'] = 24
    
    display( HTML( '<style>.container { width:100% !important; }</style>') )
    pd.options.display.max_columns = None
    pd.options.display.max_rows = None
    pd.set_option( 'display.expand_frame_repr', False )
    pd.set_option('display.float_format', lambda x: '%.4f' % x)
    
    sns.set()
    
jupyter_settings()<jupyter_output>Populating the interactive namespace from numpy and matplotlib<jupyter_text>0.2. Load Data<jupyter_code>df_raw = pd.read_csv( '../data/raw/churn.csv' )<jupyter_output><empty_output><jupyter_text>1.0. Data Description<jupyter_code>df1 = df_raw.copy()<jupyter_output><empty_output><jupyter_text>1.1. Rename Columns<jupyter_code>df1.columns = ['row_number', 'customer_id', 'surname', 'credit_score', 'geography', 'gender', 'age', 'tenure', 'balance', 'num_of_products', 'has_cr_card','is_active_member', 'estimated_salary', 'exited']<jupyter_output><empty_output><jupyter_text>1.2. Data Dimensions<jupyter_code>df1.shape<jupyter_output><empty_output><jupyter_text>1.3. Check NA<jupyter_code>df1.isna().sum()<jupyter_output><empty_output><jupyter_text>1.4. Data Dtypes<jupyter_code>df1.dtypes<jupyter_output><empty_output><jupyter_text>1.5. Descriptive Statistics    **Features*** **NowNumber:** O número da coluna* **CustomerID:** Identificador único do cliente* **Surname:** Sobrenome do cliente.* **CreditScore:** A pontuação de Crédito do cliente para o mercado de consumo.* **Geography:** O país onde o cliente reside.* **Gender:** O gênero do cliente.* **Age:** A idade do cliente.* **Tenure:** Número de anos que o cliente permaneceu ativo.* **Balance:** Valor monetário que o cliente tem em sua conta bancária.* **NumOfProducts:** O número de produtos comprado pelo cliente no banco.* **HasCrCard:** Indica se o cliente possui ou não cartão de crédito.* **IsActiveMember:** Indica se o cliente fez pelo menos uma movimentação na conta bancário dentro de 12 meses.* **EstimateSalary:** Estimativa do salário mensal do cliente.* **Exited:** Indica se o cliente está ou não em Churn.<jupyter_code>num_attr = df1.select_dtypes( include=['int64', 'float64'] )
cat_attr = df1.select_dtypes( include=['object'] )<jupyter_output><empty_output><jupyter_text>1.5.1. Numerical Attributes<jupyter_code># tendency central: mean, median
ct1 = pd.DataFrame( num_attr.apply(np.mean) )
ct2 = pd.DataFrame( num_attr.apply(np.median) )

# dispersion: min,  max, range, std
d1 = pd.DataFrame( num_attr.apply(np.min) )
d2 = pd.DataFrame( num_attr.apply(np.max) )
d3 = pd.DataFrame( num_attr.apply(lambda x: np.max(x) - np.min(x)) )
d4 = pd.DataFrame( num_attr.apply(lambda x: x.std()) )

# shape: skew, kurtosis
s1 = pd.DataFrame( num_attr.apply(lambda x: x.skew()) )
s2 = pd.DataFrame( num_attr.apply(lambda x: x.kurtosis()) )

m1 = pd.concat([d1, d2, d3 ,ct1, ct2, d4, s1, s2], axis=1).reset_index()
m1.columns = ['attribute', 'min', 'max', 'range', 'mean', 'median', 'std', 'skew', 'kurtosis']
m1<jupyter_output><empty_output><jupyter_text>num_of_products<jupyter_code>df1['num_of_products'].value_counts(normalize=True)<jupyter_output><empty_output><jupyter_text>has_cr_card<jupyter_code>df1['has_cr_card'].value_counts(normalize=True)<jupyter_output><empty_output><jupyter_text>is_active_member<jupyter_code>df1['is_active_member'].value_counts(normalize=True)<jupyter_output><empty_output><jupyter_text>exited<jupyter_code>df1['exited'].value_counts(normalize=True)<jupyter_output><empty_output><jupyter_text>1.5.2. Categorical Attributes<jupyter_code>cat_attr.describe().T<jupyter_output><empty_output><jupyter_text>geography<jupyter_code>df1['geography'].value_counts(normalize=True)<jupyter_output><empty_output><jupyter_text>gender<jupyter_code>df1['gender'].value_counts(normalize=True)<jupyter_output><empty_output><jupyter_text>2.0. Feature Engineering<jupyter_code>df2 = df1.copy()<jupyter_output><empty_output><jupyter_text>2.1. Mapa Mental de hipóteses<jupyter_code>Image('../images/mindmap-churn.png')<jupyter_output><empty_output><jupyter_text>2.2. Criação de Hipóteses   **Cliente**1. Clientes entre 40 a 60 anos, têm menos chance de abandonar o serviço comparado ao resto da baixo.2. Cliente com score card abaixo de 400 tem mais chances de abandonar o serviço.3. Clientes do sexo feminino tem 60% de manter o serviço.4. Cliente acima de 5 anos usando o  serviço tem 80% de chance de manter o serviço.5. Clientes que têm salário acima da média, têm mais chances de abandonar o serviço.6. Clientes que fazem 10 movimentações ao mês, têm mais chances de manter o serviço.7. Clientes que não têm dinheiro na poupança têm mais chances de abandonar o serviço. **Localização**1. Clientes residentes na residentes na Espanha tem mais chances de manter o serviço em comparação comparado aos outros países2. Clientes que acessam mais o portal têm mais chances de abandonar o serviço. **Marketing**1. Clientes provenientes de de afiliados, têm mais chances de manter o serviço.2. Anúncios de marketing são responsáveis pela maior quantidade de novos clientes, e não são mais fiéis à empresa do que por outros meios. **Produtos**1. Clientes que possuem cartão de crédito, tem mais chances de manter o serviço dos que não tem.  2.3. Priorização de Hipóteses * **h1.** Clientes entre 40 a 60 anos, têm menos chance de abandonar o serviço comparado ao resto da baixo.* **h2.** Cliente com score card abaixo de 400 tem mais chances de abandonar o serviço.* **h3.** Clientes do sexo feminino tem 60% de manter o serviço.* **h4.** Cliente acima de 5 anos usando o  serviço tem 80% de chance de manter o serviço.* **h5.** Clientes que têm salário acima da média, têm mais chances de abandonar o serviço.* **h6.** Clientes que não têm dinheiro na poupança têm mais chances de abandonar o serviço.* **h7.** Clientes residentes na residentes na Espanha tem mais chances de manter o serviço em comparação comparado aos outros países* **h8.** Clientes que possuem cartão de crédito, tem mais chances de manter o serviço dos que não tem.  2.4. Create Feature<jupyter_code>df2.loc[ df2['geography'] == 'France', 'country_lat'] = float(geolocator.geocode('France').raw['lat'])
df2.loc[ df2['geography'] == 'Germany', 'country_lat'] = float(geolocator.geocode('Germany').raw['lat'])
df2.loc[ df2['geography'] == 'Spain', 'country_lat'] = float(geolocator.geocode('Spain').raw['lat'])

df2.loc[ df2['geography'] == 'France', 'country_lon'] = float(geolocator.geocode('France').raw['lon'])
df2.loc[ df2['geography'] == 'Germany', 'country_lon'] = float(geolocator.geocode('Germany').raw['lon'])
df2.loc[ df2['geography'] == 'Spain', 'country_lon'] = float(geolocator.geocode('Spain').raw['lon'])<jupyter_output><empty_output><jupyter_text>3.0. Data Filtering<jupyter_code>df3 = df2.copy()
drop_cols = ['row_number', 'customer_id', 'surname']
df3 = df3.drop(drop_cols, axis=1)<jupyter_output><empty_output><jupyter_text>4.0. EDA<jupyter_code>df4 = df3.copy()<jupyter_output><empty_output><jupyter_text>5.0. Data Preprocessing<jupyter_code>df5 = df4.copy()
le = pp.LabelEncoder()

df5['geography'] = le.fit_transform( df5[['geography']].values.ravel() )
df5['gender'] = le.fit_transform( df5[['gender']].values.ravel() )<jupyter_output><empty_output><jupyter_text>6.0. Feature Selection<jupyter_code>df6 = df5.copy()<jupyter_output><empty_output><jupyter_text>7.0. Model Traning<jupyter_code>X = df6.drop('exited', axis=1)
y = df6['exited'].values
X_train, X_val, y_train, y_val = ms.train_test_split(X, y, 
                                                     test_size=0.2, 
                                                     train_size=0.8, 
                                                     random_state=42, 
                                                     shuffle=True, 
                                                     stratify=None)<jupyter_output><empty_output><jupyter_text>7.1. DummyClassifier<jupyter_code># model definition
model_baseline = dummy.DummyClassifier(strategy='prior', random_state=42, constant=None)

# model fit
model_baseline.fit( X_train, y_train )

# model predict
yhat_baseline = model_baseline.predict( X_val )

# model performance
print(metrics.classification_report( y_val, yhat_baseline,
                                    labels=None, 
                                    target_names=None, 
                                    sample_weight=None, 
                                    digits=2, 
                                    output_dict=False, 
                                    zero_division=0))<jupyter_output>precision    recall  f1-score   support

           0       0.80      1.00      0.89      1607
           1       0.00      0.00      0.00       393

    accuracy                           0.80      2000
   macro avg       0.40      0.50      0.45      2000
weighted avg       0.65      0.80      0.72      2000<jupyter_text>7.2. KNeighborsClassifier<jupyter_code># # model definition
model_knn = neighbors.KNeighborsClassifier(n_neighbors=5, 
                                           weights='uniform', 
                                           algorithm='auto', 
                                           leaf_size=30, 
                                           p=2, 
                                           metric='minkowski', 
                                           metric_params=None, 
                                           n_jobs=None)

# model fit
model_knn.fit( X_train, y_train )

# model predict
yhat_knn = model_knn.predict( X_val )

# model performance
print(metrics.classification_report( y_val, yhat_knn,
                                    labels=None, 
                                    target_names=None, 
                                    sample_weight=None, 
                                    digits=2, 
                                    output_dict=False, 
                                    zero_division=0))<jupyter_output>precision    recall  f1-score   support

           0       0.81      0.93      0.86      1607
           1       0.24      0.09      0.14       393

    accuracy                           0.76      2000
   macro avg       0.52      0.51      0.50      2000
weighted avg       0.70      0.76      0.72      2000<jupyter_text>7.3 SVM<jupyter_code># model definition
model_svm = svm.SVC(C=1.0, 
                    kernel='rbf', 
                    degree=3, 
                    gamma='scale', 
                    coef0=0.0, 
                    shrinking=True, 
                    probability=False, 
                    tol=0.001, 
                    cache_size=200, 
                    class_weight=None, 
                    verbose=False, 
                    max_iter=-1, 
                    decision_function_shape='ovr', 
                    break_ties=False, 
                    random_state=42)
# model fit
model_svm.fit( X_train, y_train )

# model predict
yhat_svm = model_svm.predict( X_val )

# model performance
print(metrics.classification_report( y_val, yhat_svm,
                                    labels=None, 
                                    target_names=None, 
                                    sample_weight=None, 
                                    digits=2, 
                                    output_dict=False, 
                                    zero_division=0))<jupyter_output>precision    recall  f1-score   support

           0       0.80      1.00      0.89      1607
           1       0.00      0.00      0.00       393

    accuracy                           0.80      2000
   macro avg       0.40      0.50      0.45      2000
weighted avg       0.65      0.80      0.72      2000<jupyter_text>7.4. RandomForestClassifier<jupyter_code># model definition
model_rf = ensemble.RandomForestClassifier(n_estimators=100, 
                                           criterion='gini', 
                                           max_depth=None, 
                                           min_samples_split=2, 
                                           min_samples_leaf=1, 
                                           min_weight_fraction_leaf=0.0, 
                                           max_features='auto', 
                                           max_leaf_nodes=None, 
                                           min_impurity_decrease=0.0, 
                                           min_impurity_split=None, 
                                           bootstrap=True, 
                                           oob_score=False, 
                                           n_jobs=None, 
                                           random_state=42, 
                                           verbose=0, 
                                           warm_start=False, 
                                           class_weight=None, 
                                           ccp_alpha=0.0, 
                                           max_samples=None)
# model fit
model_rf.fit( X_train, y_train )

# model predict
yhat_rf = model_rf.predict( X_val )

# model performance
print(metrics.classification_report( y_val, yhat_rf,
                                    labels=None, 
                                    target_names=None, 
                                    sample_weight=None, 
                                    digits=2, 
                                    output_dict=False, 
                                    zero_division=0))<jupyter_output>precision    recall  f1-score   support

           0       0.88      0.96      0.92      1607
           1       0.76      0.47      0.58       393

    accuracy                           0.87      2000
   macro avg       0.82      0.72      0.75      2000
weighted avg       0.86      0.87      0.85      2000<jupyter_text>7.5. LogisticRegression<jupyter_code># model definition
model_lr = linear_model.LogisticRegression(penalty='l2', 
                                           dual=False, 
                                           tol=0.0001, 
                                           C=1.0, 
                                           fit_intercept=True, 
                                           intercept_scaling=1, 
                                           class_weight=None, 
                                           random_state=42, 
                                           solver='lbfgs', 
                                           max_iter=100, 
                                           multi_class='auto', 
                                           verbose=0, 
                                           warm_start=False, 
                                           n_jobs=None, 
                                           l1_ratio=None)
# model fit
model_lr.fit( X_train, y_train )

# model predict
yhat_lr = model_lr.predict( X_val )

# model performance
print(metrics.classification_report( y_val, yhat_lr,
                                    labels=None, 
                                    target_names=None, 
                                    sample_weight=None, 
                                    digits=2, 
                                    output_dict=False, 
                                    zero_division=0))<jupyter_output>precision    recall  f1-score   support

           0       0.81      0.98      0.89      1607
           1       0.42      0.07      0.13       393

    accuracy                           0.80      2000
   macro avg       0.62      0.52      0.51      2000
weighted avg       0.73      0.80      0.74      2000
{'fraction_non_alphanumeric': 0.09409878522538077, 'fraction_numerical': 0.03410001849910588, 'mean_word_length': 1.8318491356731272, 'pattern_counts': {'":': 0, '<': 117, '<?xml version=': 0, '>': 117, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 138, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '30', 'dir': 'jupyter-structured-clean-dedup', 'id': '29890', 'license': 'MIT', 'n_tokens_mistral': 5186, 'n_tokens_neox': 4773, 'n_words': 1066, 'path': 'notebooks/c03-feature_engineering.ipynb', 'repo_name': 'cidosjr/churn-prediction', 'size': '16217'}