<jupyter_start><jupyter_text>Dataset Link: https://archive.ics.uci.edu/ml/datasets/Bank+Marketing Attribute Information: Input variables: bank client data: 1 - age (numeric) 2 - job : type of job (categorical: 'admin.','blue-collar','entrepreneur','housemaid','management','retired','self-employed','services','student','technician','unemployed','unknown') 3 - marital : marital status (categorical: 'divorced','married','single','unknown'; note: 'divorced' means divorced or widowed) 4 - education (categorical: 'basic.4y','basic.6y','basic.9y','high.school','illiterate','professional.course','university.degree','unknown') 5 - default: has credit in default? (categorical: 'no','yes','unknown') 6 - housing: has housing loan? (categorical: 'no','yes','unknown') 7 - loan: has personal loan? (categorical: 'no','yes','unknown') Related with the last contact of the current campaign: 8 - contact: contact communication type (categorical: 'cellular','telephone')  9 - month: last contact month of year (categorical: 'jan', 'feb', 'mar', ..., 'nov', 'dec') 10 - day_of_week: last contact day of the week (categorical: 'mon','tue','wed','thu','fri') 11 - duration: last contact duration, in seconds (numeric). Important note: this attribute highly affects the output target (e.g., if duration=0 then y='no'). Yet, the duration is not known before a call is performed. Also, after the end of the call y is obviously known. Thus, this input should only be included for benchmark purposes and should be discarded if the intention is to have a realistic predictive model. Other attributes: 12 - campaign: number of contacts performed during this campaign and for this client (numeric, includes last contact) 13 - pdays: number of days that passed by after the client was last contacted from a previous campaign (numeric; 999 means client was not previously contacted) 14 - previous: number of contacts performed before this campaign and for this client (numeric) 15 - poutcome: outcome of the previous marketing campaign (categorical: 'failure','nonexistent','success') Social and economic context attributes 16 - emp.var.rate: employment variation rate - quarterly indicator (numeric) 17 - cons.price.idx: consumer price index - monthly indicator (numeric)  18 - cons.conf.idx: consumer confidence index - monthly indicator (numeric)  19 - euribor3m: euribor 3 month rate - daily indicator (numeric) 20 - nr.employed: number of employees - quarterly indicator (numeric) Output variable (desired target): 21 - y - has the client subscribed a term deposit? (binary: 'yes','no')<jupyter_code>from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras import optimizers
from sklearn.metrics import confusion_matrix
import tensorflow as tf
import keras
from tensorflow.keras.callbacks import TensorBoard
from sklearn.utils import class_weight
from collections import Counter
%matplotlib notebook
import base64
import sys
sys.path.append('./python')
from generic_feature_statistics_generator import GenericFeatureStatisticsGenerator
from IPython.core.display import display, HTML
import time<jupyter_output>Using TensorFlow backend.<jupyter_text>Import data<jupyter_code>df = pd.read_csv('bank-additional-full.csv', delimiter=';')
df = df.drop('duration', axis=1)
target = df['y'].replace(['yes', 'no'], (1,0))
df_overview = df.copy()
df_overview['y']= target
df_overview.head()<jupyter_output><empty_output><jupyter_text>Check data using : «facets: https://github.com/PAIR-code/facets»<jupyter_code>X_train_temp, X_test_temp, y_train_temp, y_test = train_test_split(df_overview, target, test_size=0.5)
gfsg = GenericFeatureStatisticsGenerator()
proto = gfsg.ProtoFromDataFrames([{'name': 'train', 'table': X_train_temp},
                                  {'name': 'test', 'table': X_test_temp}])
protostr = base64.b64encode(proto.SerializeToString()).decode("utf-8")
HTML_TEMPLATE = """<link rel="import" 
                href="https://raw.githubusercontent.com/PAIR-code/facets/master/facets-dist/facets-jupyter.html" >
        <facets-overview id="elem"></facets-overview>
        <script>
          document.querySelector("#elem").protoInput = "{protostr}";
        </script>"""
html = HTML_TEMPLATE.format(protostr=protostr)
display(HTML(html))<jupyter_output><empty_output><jupyter_text>Notes: Column: 'previous'  have ~86% zero values. Column: 'pdays' Frequency of :'999' 39673 times. Column: 'default' { 'no': 32588 , 'unknown': 8597 'yes': 3 } yes:3 times. Column: 'poutcome' Frequency value 'nonexistent': 35563 times Column: 'y' Target/Label Imbalance dataset (0: 36548, 1: 4640) . Metrics to optimize : F1 ,recall etc but not accuracy<jupyter_code>print('Class imbalance, Positives (1):',(100*(target.value_counts()[1] / (sum(Counter(target).values())))),'Percent')
Counter(target)
Counter(df['pdays'])
Counter(df['poutcome'])
Counter(df['default'])<jupyter_output><empty_output><jupyter_text>Based on the above info:<jupyter_code>x_data = df.drop(['y','default', 'previous','pdays','poutcome'], axis=1)
target = df['y'].replace(['yes', 'no'], (1,0))<jupyter_output><empty_output><jupyter_text>get_dummies()<jupyter_code># Save column names if they are an object.
cat_cols = []
for c in x_data.columns:
    if x_data[c].dtype == 'object':
        cat_cols.append(c)
cat_cols
for col in cat_cols: # 
    x_data = pd.get_dummies(x_data, columns=[col], drop_first=True)
x_data.head()<jupyter_output><empty_output><jupyter_text>Data split 50/50<jupyter_code>X_train, X_test, y_train, y_test = train_test_split(x_data, target, test_size=0.5)<jupyter_output><empty_output><jupyter_text>Normalization using StandarScaler()<jupyter_code>scaler = StandardScaler()
scaler.fit(X_train)
X_train = pd.DataFrame(scaler.transform(X_train),
                              columns=X_train.columns,
                              index=X_train.index)
X_train.head()
X_test = pd.DataFrame(scaler.transform(X_test),
                             columns=X_test.columns,
                             index=X_test.index)
X_test.head()<jupyter_output><empty_output><jupyter_text>Sequential Model<jupyter_code>model = Sequential()
model.add(Dense(46, input_dim=46, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(32, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(32, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(1, activation='sigmoid'))
model.summary()
model.compile(loss='binary_crossentropy',
              optimizer=optimizers.adam(lr=0.01),
              metrics=['accuracy'])<jupyter_output><empty_output><jupyter_text>Calculate the weights<jupyter_code>class_weights = class_weight.compute_class_weight('balanced',
                                                 np.unique(y_train),
                                                 y_train)
class_weights
wght= {0:class_weights[0],1:class_weights[1]}
wght<jupyter_output><empty_output><jupyter_text>Train<jupyter_code>keras.backend.get_session().run(tf.global_variables_initializer())
NAME = 'test-{}'.format(int(time.time()))
tensorboard = TensorBoard(log_dir='.logs/10_3232_{}'.format(NAME))
model.fit(X_train, y_train,
          shuffle=True,
          class_weight=wght,
          validation_split=0.3,
          epochs=10,
          batch_size=128,
          verbose=2,
          callbacks=[tensorboard])<jupyter_output>Train on 14415 samples, validate on 6179 samples
Epoch 1/10
 - 0s - loss: 0.5531 - acc: 0.8257 - val_loss: 0.5299 - val_acc: 0.8461
Epoch 2/10
 - 0s - loss: 0.5552 - acc: 0.8180 - val_loss: 0.5247 - val_acc: 0.8411
Epoch 3/10
 - 0s - loss: 0.5565 - acc: 0.8181 - val_loss: 0.5399 - val_acc: 0.8388
Epoch 4/10
 - 0s - loss: 0.5553 - acc: 0.8300 - val_loss: 0.5330 - val_acc: 0.8395
Epoch 5/10
 - 0s - loss: 0.5561 - acc: 0.8148 - val_loss: 0.5294 - val_acc: 0.8217
Epoch 6/10
 - 0s - loss: 0.5500 - acc: 0.8148 - val_loss: 0.5437 - val_acc: 0.8162
Epoch 7/10
 - 0s - loss: 0.5564 - acc: 0.8231 - val_loss: 0.5354 - val_acc: 0.8501
Epoch 8/10
 - 0s - loss: 0.5493 - acc: 0.8238 - val_loss: 0.5389 - val_acc: 0.8283
Epoch 9/10
 - 0s - loss: 0.5487 - acc: 0.8251 - val_loss: 0.5339 - val_acc: 0.8335
Epoch 10/10
 - 0s - loss: 0.5504 - acc: 0.8239 - val_loss: 0.5304 - val_acc: 0.8391<jupyter_text>Model Evaluation. (Not really needed)<jupyter_code>score = model.evaluate(X_test, y_test, batch_size=128)
print('Test accuracy:', score[1])<jupyter_output>Test accuracy: 0.8367000096247383<jupyter_text>Predictions<jupyter_code>final_preds = pd.DataFrame(model.predict(X_test), index=y_test.index)
# Predict without setting threshold: 
#         final_preds = pd.DataFrame(model.predict_classes(X_test), index=y_test.index)
final_preds[final_preds<0.4]=0
final_preds[final_preds>=0.4]=1
final_preds=final_preds.astype('int64')
cm = confusion_matrix(y_true=y_test, y_pred=final_preds)
cm
print(classification_report(y_test, final_preds))<jupyter_output>precision    recall  f1-score   support

           0       0.95      0.83      0.88     18250
           1       0.32      0.64      0.43      2344

   micro avg       0.81      0.81      0.81     20594
   macro avg       0.63      0.73      0.66     20594
weighted avg       0.88      0.81      0.83     20594
{'fraction_non_alphanumeric': 0.1310285958173282, 'fraction_numerical': 0.052603499786598375, 'mean_word_length': 4.349885844748859, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 55, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '238766', 'license': 'MIT', 'n_tokens_mistral': 3423, 'n_tokens_neox': 3090, 'n_words': 757, 'path': 'Classification_example_with_Keras_Classifier_Final.ipynb', 'repo_name': 'LeoTserr/Classification_example_with_Keras_Classifier', 'size': '9372'}