<jupyter_start><jupyter_text>Cargar los datos<jupyter_code>credit=pd.read_csv("Credit.csv")
credit.head()<jupyter_output><empty_output><jupyter_text>EDA (Exploratory Data Analysis)<jupyter_code># Check los missing values
credit.isnull().sum()
msno.matrix(credit)<jupyter_output><empty_output><jupyter_text>Comprobando el balance de la data<jupyter_code>print('El número por incumplimento de pago son: ' + str(credit['morosidad.mes.siguiente'].value_counts()[0]) + ' lo que es el', round(credit['morosidad.mes.siguiente'].value_counts()[0]/len(credit) * 100,2), '% del dataset')
print('El número por cumplimiento de pago son: ' + str(credit['morosidad.mes.siguiente'].value_counts()[1]) + ' lo que es el', round(credit['morosidad.mes.siguiente'].value_counts()[1]/len(credit) * 100,2), '% del dataset')<jupyter_output>El número por incumplimento de pago son: 23364 lo que es el 77.88 % del dataset
El número por cumplimiento de pago son: 6636 lo que es el 22.12 % del dataset<jupyter_text>Se puede observar que hay un desequilibrio en el conjunto de datos. Este problema se arreglará más adelante. A continuación se presenta una imagen que sustenta lo anterior.<jupyter_code>sns.countplot(x='morosidad.mes.siguiente', data=credit)
# Medidas del grafico
fig, ax = plt.subplots(figsize=(20,10))         

# Graficar la matrix
corr = credit.corr()
sns.heatmap(corr, cmap='YlGnBu', annot_kws={'size':30}, ax=ax)
ax.set_title("Matrix de correlación desiquilibrada", fontsize=20)

plt.show()
#my_report = sv.analyze(credit)
#my_report.show_html('Report_desquilibrado.html')<jupyter_output><empty_output><jupyter_text>Feature Engineering**1. Escalar los datos:** Se usa **RobustScaler** ya es resistente a los valores atípicos y sabe manejarlos dado el caso que se presenten en el conjunto de datos.<jupyter_code>def escalador(data):
    """
    escalador: Esta función escala los datos con RobustScaler
    
    Return
    ------
    data: Dataframe con las variables numericas escaladas
    
    """
    from sklearn.preprocessing import RobustScaler
    
    # Columnas para escalar
    columns = ['MONTO_EST_CUENTA1', 'MONTO_EST_CUENTA2', 'MONTO_EST_CUENTA3', 
               'MONTO_EST_CUENTA4', 'MONTO_EST_CUENTA5', 'MONTO_EST_CUENTA6', 
               'PAGOS_ANT1', 'PAGOS_ANT2', 'PAGOS_ANT3', 'PAGOS_ANT4', 'PAGOS_ANT5', 'PAGOS_ANT6']
    
    Scaler = RobustScaler()
    data[columns] = Scaler.fit_transform(data[columns])
    
    return data   
    
data_escalada = escalador(credit)
data_escalada.head()<jupyter_output><empty_output><jupyter_text>Solución del problema de desequilibrioEl **sobremuestreo (Oversampling)** aleatorio implica la duplicación aleatoria de ejemplos de la clase minoritaria y su adición al conjunto de datos de entrenamiento.El **submuestreo (Undersampling)** aleatorio implica la selección aleatoria de ejemplos de la clase mayoritaria para eliminarlos del conjunto de datos de entrenamiento.Para este proyecto se utilizará este último. A continuación se observa una función que hace el procedimiento.<jupyter_code>def undersampling_data(data):
    """
    undersampling_data : Recibe un dataframe que se encuentra desquilibrado y retorna un dataframe equilibrado 
                         con igual numero de clases
    
    Return
    ------
    data: Dataframe equilibrado con igual numero de clases
    
    """
    # Datos aleatorios.
    shuffled_df = data.sample(frac=1,random_state=4)

    # Cantidad de clases a escoger. Se especifica la clase que tiene menos datos
    morosos_dt = shuffled_df.loc[shuffled_df['morosidad.mes.siguiente'] == 1]

    # Seleccionar aleatoriamente el numero de datos. Se especifica la clase que tiene mas datos
    rows = data['morosidad.mes.siguiente'].value_counts()[1]
    no_morosos_dt = shuffled_df.loc[shuffled_df['morosidad.mes.siguiente'] == 0].sample(n=rows,random_state=42)
    normalized_df = pd.concat([morosos_dt, no_morosos_dt])
    
    return normalized_df   
    
data_normalizada = undersampling_data(data_escalada)
sns.countplot(x='morosidad.mes.siguiente', data=data_normalizada)
print('El número por incumplimento de pago son: ' + str(data_normalizada['morosidad.mes.siguiente'].value_counts()[0]) + ' lo que es el', round(data_normalizada['morosidad.mes.siguiente'].value_counts()[0]/len(data_normalizada) * 100,2), '% del dataset')
print('El número por cumplimiento de pago son: ' + str(data_normalizada['morosidad.mes.siguiente'].value_counts()[1]) + ' lo que es el', round(data_normalizada['morosidad.mes.siguiente'].value_counts()[1]/len(data_normalizada) * 100,2), '% del dataset')
fig, ax = plt.subplots(figsize=(20,10))         

# Matrix de correlación balanceada
corr = data_normalizada.corr()
sns.heatmap(corr, cmap='YlGnBu', annot_kws={'size':30}, ax=ax)
ax.set_title("Matrix de correlación balanceada", fontsize=20)

plt.show()<jupyter_output><empty_output><jupyter_text>Hay pequeñas difencias en las matrices de relación de los dos dataframes. Para ello se generá dos reportes donde se puede apreciar con mayor exactitud las diferencias.<jupyter_code>#my_report = sv.analyze(data_normalizada)
#my_report.show_html('Report_normalizada.html')<jupyter_output><empty_output><jupyter_text>Valores atípícos<jupyter_code># Tamaño de los graficos
fig, axes = plt.subplots(nrows=6, ncols=3, figsize=(30,40))

# Negative Correlations with our Class (The lower our feature value the more likely it will be a fraud transaction)
sns.boxplot(x="morosidad.mes.siguiente", y="MONTO_CREDITO", data=data_normalizada, ax=axes[0][0])
axes[0][0].set_title('Monto crédito')

sns.boxplot(x="morosidad.mes.siguiente", y="PAGO_0", data=data_normalizada, ax=axes[0][1])
axes[0][1].set_title('PAGO_0')

sns.boxplot(x="morosidad.mes.siguiente", y="PAGO_2", data=data_normalizada, ax=axes[0][2])
axes[0][2].set_title('PAGO_2')

sns.boxplot(x="morosidad.mes.siguiente", y="PAGO_3", data=data_normalizada, ax=axes[1][0])
axes[1][0].set_title('PAGO_3')

sns.boxplot(x="morosidad.mes.siguiente", y="PAGO_4", data=data_normalizada, ax=axes[1][1])
axes[1][1].set_title('PAGO_4')

sns.boxplot(x="morosidad.mes.siguiente", y="PAGO_5", data=data_normalizada, ax=axes[1][2])
axes[1][2].set_title('PAGO_5')

sns.boxplot(x="morosidad.mes.siguiente", y="PAGO_6", data=data_normalizada, ax=axes[2][0])
axes[2][0].set_title('PAGO_6')

sns.boxplot(x="morosidad.mes.siguiente", y="MONTO_EST_CUENTA1", data=data_normalizada, ax=axes[2][1])
axes[2][1].set_title('MONTO_EST_CUENTA1')

sns.boxplot(x="morosidad.mes.siguiente", y="MONTO_EST_CUENTA2", data=data_normalizada, ax=axes[2][2])
axes[2][2].set_title('MONTO_EST_CUENTA2')

sns.boxplot(x="morosidad.mes.siguiente", y="MONTO_EST_CUENTA3", data=data_normalizada, ax=axes[3][0])
axes[3][0].set_title('MONTO_EST_CUENTA3')

sns.boxplot(x="morosidad.mes.siguiente", y="MONTO_EST_CUENTA4", data=data_normalizada, ax=axes[3][1])
axes[3][1].set_title('MONTO_EST_CUENTA4')

sns.boxplot(x="morosidad.mes.siguiente", y="MONTO_EST_CUENTA5", data=data_normalizada, ax=axes[3][2])
axes[3][2].set_title('MONTO_EST_CUENTA5')

sns.boxplot(x="morosidad.mes.siguiente", y="MONTO_EST_CUENTA6", data=data_normalizada, ax=axes[4][0])
axes[4][0].set_title('MONTO_EST_CUENTA6')

sns.boxplot(x="morosidad.mes.siguiente", y="PAGOS_ANT1", data=data_normalizada, ax=axes[4][1])
axes[4][1].set_title('PAGOS_ANT1')

sns.boxplot(x="morosidad.mes.siguiente", y="PAGOS_ANT2", data=data_normalizada, ax=axes[4][2])
axes[4][2].set_title('PAGOS_ANT2')

sns.boxplot(x="morosidad.mes.siguiente", y="PAGOS_ANT3", data=data_normalizada, ax=axes[5][0])
axes[5][0].set_title('PAGOS_ANT3')

sns.boxplot(x="morosidad.mes.siguiente", y="PAGOS_ANT4", data=data_normalizada, ax=axes[5][1])
axes[5][1].set_title('PAGOS_ANT4')

sns.boxplot(x="morosidad.mes.siguiente", y="PAGOS_ANT5", data=data_normalizada, ax=axes[5][2])
axes[5][2].set_title('PAGOS_ANT5')

plt.show()


# Eliminar columna index y la columna ID
data_normalizada.reset_index(drop=True, inplace=True)
data_normalizada.drop(['ID'], axis=1, inplace=True)

data_normalizada.head()<jupyter_output><empty_output><jupyter_text>Feature importancesSe realizaron diferentes pruebas con clasificadores tales como: Randon Forest, ExtraTreesClassifier, Ada Boost y Gradient Boosting siendo este último el que obtuvo una mayor precisión.<jupyter_code>def features_impotances(df_normalizada):
    """
    features_impotances: Esta función encuentra las variables más importantes aplicando el clasificador 
                         de Gradient Boosting. Posteriormente determina la precisión del clasificador
                         para encontrar las features más importantes.
                         
    Parameters
    ----------
    df_normalizada: DataFrame normalizado.
    
    Returns
    -------
    dataframe : Dataframe que será entrenado para el modelo de machine learning
    """
    
    # y hace referencia a la columna del target
    X, y = df_normalizada.iloc[:,:-1], df_normalizada.iloc[:,-1]
    
    # Separar la data con un 70% de entrenamiento y 30% de prueba
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=4444, stratify=y)
    
    # Crear un clasificador de gradient boosting
    clf = GradientBoostingClassifier(n_estimators=100, random_state=4444)
    
    # Entrenar el clasificador 
    clf.fit(X_train, y_train)
    
    # Crear un objeto selector que utilizará el clasificador de random forest para identificar
    # características que tienen una importancia de más de 0.03
    sfm = SelectFromModel(clf, threshold=0.03)

    # Entrenar el selector
    sfm.fit(X_train, y_train)

    # Imprimir los nombre de las columnas más importantes
    i = 1
    columns = []
    for feature_list_index in sfm.get_support(indices=True):
        #print(f'{i}: {df_normalizada.columns[feature_list_index]}')
        columns.append(df_normalizada.columns[feature_list_index])
        i += 1
        
    # Aplicar el clasificador con todas las funciones a los datos de prueba
    y_pred = clf.predict(X_test)

    # Imprimir la precisión del modelo de entrenado para detectar las features mas importantes
    #print(f'La precisión es: {accuracy_score(y_test, y_pred).round(3)}')
    
    columns.append('morosidad.mes.siguiente')
    final_data = df_normalizada[columns]

    return final_data
final_data = features_impotances(data_normalizada)
final_data.head()<jupyter_output><empty_output><jupyter_text>Eliminar los outilers (valores atípicos)<jupyter_code># Dividir en elementos de entrada y salida
split_data = final_data.to_numpy()
X, y = split_data[:, :-1], split_data[:, -1]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=4444, stratify=y)
print(f"y_train: {Counter(y_train)}")
print(f"y_test: {Counter(y_test)}")

# Imprime las dimensiones
with_outilers = X_train.shape[0]
print(X_train.shape, y_train.shape)

# Identifica valores atípicos en el conjunto de datos de entrenamiento
iso = IsolationForest(contamination=0.1)
yhat = iso.fit_predict(X_train)

# Selecciona todas las filas que no sean valores atípicos
mask = yhat != -1
X_train, y_train = X_train[mask, :], y_train[mask]
without_outliers = X_train.shape[0]

# Imprime las dimensiones
print(X_train.shape, y_train.shape)

print(f"En total se detectaron {with_outilers - without_outliers} valores atípicos en el dataset.")<jupyter_output>y_train: Counter({1.0: 4446, 0.0: 4446})
y_test: Counter({0.0: 2190, 1.0: 2190})
(8892, 6) (8892,)
(8002, 6) (8002,)
En total se detectaron 890 valores atípicos en el dataset.<jupyter_text>Implementación de algoritmos  1) Regresión logistica<jupyter_code>def log_regr(X_train, X_test, y_train, y_test):
    """
    log_regr: Esta función implementa el algoritmo de regresión logística y guarda en un 
              diccionario las metricas
    
    Return
    ------
    metrics: Retorna un diccinario con las metricas del modelo implementado.
    """
    clf = LogisticRegression(random_state=4444)
    clf.fit(X_train, y_train)
    
    y_pred = clf.predict(X_test)
    
    # Guardar metricas en un diccionario
    metrics = {}
    
    metrics ['clf'] = clf
    metrics['accuracy'] = accuracy_score(y_test, y_pred)
    metrics ['precision'] = precision_score(y_test, y_pred, average = 'weighted')
    metrics ['recall'] = recall_score(y_test, y_pred, average='weighted')
    metrics ['f1'] = f1_score(y_test, y_pred, average='weighted')
    
    return metrics

log_reg_result = log_regr(X_train, X_test, y_train, y_test)
log_reg_result<jupyter_output>C:\ProgramData\Anaconda3\lib\site-packages\sklearn\metrics\_classification.py:1221: UndefinedMetricWarning: Precision is ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.
  _warn_prf(average, modifier, msg_start, len(result))<jupyter_text>2) Random Forest<jupyter_code>def r_forest(X_train, X_test, y_train, y_test):
    """
    r_forest: Esta función implementa el algoritmo de random forest y guarda en un diccionario las metricas
    
    Return
    ------
    metrics: Retorna un diccinario con las metricas del modelo implementado.
    
    """    
    clf = RandomForestClassifier(random_state=4444)
    clf.fit(X_train, y_train)
    
    y_pred = clf.predict(X_test)
    
    # Guardar metricas en un diccionario
    metrics = {}
    
    metrics ['clf'] = clf
    metrics['accuracy'] = accuracy_score(y_test, y_pred)
    metrics ['precision'] = precision_score(y_test, y_pred,average='weighted')
    metrics ['recall'] = recall_score(y_test, y_pred,average='weighted')
    metrics ['f1'] = f1_score(y_test,y_pred,average='weighted')
    
    return metrics

r_forest_result = r_forest(X_train, X_test, y_train, y_test)
r_forest_result<jupyter_output><empty_output><jupyter_text>3) Gradient Boosting<jupyter_code>def g_boosting(X_train, X_test, y_train, y_test):
    """
    g_boosting: Esta función implementa el algoritmo de Gradient Boosting y guarda en un diccionario las metricas
    
    Return
    ------
    metrics: Retorna un diccinario con las metricas del modelo implementado.
    
    """    
    clf = GradientBoostingClassifier(random_state=4444)
    clf.fit(X_train, y_train)
    
    y_pred = clf.predict(X_test)
    
    # Guardar metricas en un diccionario
    metrics = {}
    
    metrics ['clf'] = clf
    metrics['accuracy'] = accuracy_score(y_test, y_pred)
    metrics ['precision'] = precision_score(y_test, y_pred,average='weighted')
    metrics ['recall'] = recall_score(y_test, y_pred,average='weighted')
    metrics ['f1'] = f1_score(y_test,y_pred,average='weighted')
    
    return metrics

g_boosting_result = g_boosting(X_train, X_test, y_train, y_test)
g_boosting_result<jupyter_output><empty_output><jupyter_text>4) Ada Boost<jupyter_code>def ada_boost(X_train, X_test, y_train, y_test):
    """
    ada_boost: Esta función implementa el algoritmo de ada boosting y guarda en un diccionario las metricas
    
    Return
    ------
    metrics: Retorna un diccinario con las metricas del modelo implementado.
    
    """    
    clf = AdaBoostClassifier(random_state=4444)
    clf.fit(X_train, y_train)
    
    y_pred = clf.predict(X_test)
    
    # Guardar metricas en un diccionario
    metrics = {}
    
    metrics ['clf'] = clf
    metrics['accuracy'] = accuracy_score(y_test, y_pred)
    metrics ['precision'] = precision_score(y_test, y_pred,average='weighted')
    metrics ['recall'] = recall_score(y_test, y_pred,average='weighted')
    metrics ['f1'] = f1_score(y_test,y_pred,average='weighted')
    
    return metrics

ada_boost_result = ada_boost(X_train, X_test, y_train, y_test)
ada_boost_result<jupyter_output><empty_output><jupyter_text>5)  Voting<jupyter_code>def voting(X_train, X_test, y_train, y_test, rf, gb, ad):
    """
    voting: Esta función implementa varios algoritmos y guarda en un diccionario las metricas
    
    Return
    ------
    metrics: Retorna un diccinario con las metricas del modelo implementado.
    
    """    
    clf = VotingClassifier(estimators=[('rf',rf),('gb', gb),('ab',ad)])
    clf.fit(X_train, y_train)
    
    y_pred = clf.predict(X_test)
    
    # Guardar metricas en un diccionario
    metrics = {}
    
    metrics ['clf'] = clf
    metrics['accuracy'] = accuracy_score(y_test, y_pred)
    metrics ['precision'] = precision_score(y_test, y_pred,average='weighted')
    metrics ['recall'] = recall_score(y_test, y_pred,average='weighted')
    metrics ['f1'] = f1_score(y_test,y_pred,average='weighted')
    
    return metrics

voting_result = voting(X_train, X_test, y_train, y_test,
                       r_forest_result.get('clf'), g_boosting_result.get('clf'),
                       ada_boost_result.get('clf'))
voting_result<jupyter_output><empty_output><jupyter_text>6)  LightGBM<jupyter_code>def lgb_model(X_train, X_test, y_train, y_test):
    """
    lgb_model: Esta función implementa el algoritmo de LightGBM y guarda en un diccionario las metricas
    
    Return
    ------
    metrics: Retorna un diccinario con las metricas del modelo implementado.
    
    """
    import lightgbm
    clf = LGBMClassifier()
    clf.fit(X_train, y_train)
    
    y_pred = clf.predict(X_test)
    
    # Guardar metricas en un diccionario
    metrics = {}
    
    metrics ['clf'] = clf
    metrics['accuracy'] = accuracy_score(y_test, y_pred)
    metrics ['precision'] = precision_score(y_test, y_pred,average='weighted')
    metrics ['recall'] = recall_score(y_test, y_pred,average='weighted')
    metrics ['f1'] = f1_score(y_test,y_pred,average='weighted')
    
    return metrics

lgb_result = lgb_model(X_train, X_test, y_train, y_test)
lgb_result<jupyter_output><empty_output><jupyter_text>Con el objetivo de graficar cada uno de los resultados cada una de las metricas se almaceneran en una lista.<jupyter_code># Todos los scores en una lista
accuracy=[]
accuracy.append(log_reg_result.get('accuracy'))
accuracy.append(r_forest_result.get('accuracy'))
accuracy.append(g_boosting_result.get('accuracy'))
accuracy.append(ada_boost_result.get('accuracy'))
accuracy.append(voting_result.get('accuracy'))
accuracy.append(lgb_result.get('accuracy'))
precision=[]
precision.append(log_reg_result.get('precision'))
precision.append(r_forest_result.get('precision'))
precision.append(g_boosting_result.get('precision'))
precision.append(ada_boost_result.get('precision'))
precision.append(voting_result.get('precision'))
precision.append(lgb_result.get('precision'))
recall=[]
recall.append(log_reg_result.get('recall'))
recall.append(r_forest_result.get('recall'))
recall.append(g_boosting_result.get('recall'))
recall.append(ada_boost_result.get('recall'))
recall.append(voting_result.get('recall'))
recall.append(lgb_result.get('recall'))
f1=[]
f1.append(log_reg_result.get('f1'))
f1.append(r_forest_result.get('f1'))
f1.append(g_boosting_result.get('f1'))
f1.append(ada_boost_result.get('f1'))
f1.append(voting_result.get('f1'))
f1.append(lgb_result.get('f1'))
print(accuracy)
print(precision)
print(recall)
print(f1)<jupyter_output>[0.5, 0.6755707762557077, 0.7091324200913242, 0.6929223744292238, 0.7070776255707762, 0.7025114155251142]
[0.25, 0.6793766917983555, 0.7146784937960651, 0.7044021093330098, 0.7156648746800037, 0.7085615306601651]
[0.5, 0.6755707762557077, 0.7091324200913242, 0.6929223744292238, 0.7070776255707762, 0.7025114155251142]
[0.3333333333333333, 0.6738407093484293, 0.707241616377664, 0.6885494129829709, 0.704132444527795, 0.700338209941985]<jupyter_text>Graficar los resultados de las metricas Acurracy<jupyter_code>classifier_names=('Log_reg','random_forst','grad_boost','adaboost','voting_class', 'ligth_gbm')
y_axis=np.arange(len(classifier_names))

plt.bar(y_axis, accuracy, alpha=0.4, color='navy', ecolor='navy')
plt.xticks(y_axis, classifier_names)
plt.ylabel('Accuracy Scores')
plt.title('Comparación de los clasificadores con repecto a Accuracy')

plt.show()<jupyter_output><empty_output><jupyter_text>Precision<jupyter_code>plt.bar(y_axis, precision, alpha=0.4,color='purple',ecolor='darkgreen')
plt.xticks(y_axis, classifier_names)
plt.ylabel('Precision Scores')
plt.title('Comparación de los clasificadores con repecto a Precision')

plt.show()<jupyter_output><empty_output><jupyter_text>Recall<jupyter_code>plt.bar(y_axis, recall, alpha=0.4,color='orange',ecolor='black')
plt.xticks(y_axis, classifier_names)
plt.ylabel('Recall Scores')
plt.title('Comparación de los clasificadores con repecto a Recall')

plt.show()<jupyter_output><empty_output><jupyter_text>f1<jupyter_code>plt.bar(y_axis, f1, alpha=0.4,color='brown',ecolor='black')
plt.xticks(y_axis, classifier_names)
plt.ylabel('F1 Scores')
plt.title('Comparación de los clasificadores con repecto a F1 Score')

plt.show()<jupyter_output><empty_output><jupyter_text>Ajustes de hiperparametros  Randon Forest<jupyter_code>def hyperparameters_rf(data):
    """
    hyperparameters_rf: Encuentra los mejores hiperparametros para el algoritmo de random
                        forest del conjunto de datos.
                        
    data: Conjunto de datos
    
    Return
    ------
    None    
    """

    data = data.sample(frac=0.2, random_state=4444)
    
    data = data.to_numpy()

    # Separar los datos de la etiqueta
    X, y = data[:, :-1], data[:, -1]

    # define el modelo
    clf = RandomForestClassifier()

    # define evaluation
    cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=4444)

    # define search space
    space = dict()
    space['n_estimators'] = list(range(100, 550, 50))
    space['max_depth'] = list(range(5, 100, 10))
    space['min_samples_split'] = list(range(2, 50, 10))
    space['min_samples_leaf'] = list(range(1, 12, 2))

    search = RandomizedSearchCV(clf, space, n_iter=100,
                                scoring='accuracy', n_jobs=-1, cv=cv,
                                random_state=4444)

    # execute search
    result = search.fit(X, y)
    # summarize result
    print('Best Score: %s' % result.best_score_)
    print('Best Hyperparameters: %s' % result.best_params_)

    return None
best_param_rf = hyperparameters_rf(final_data)<jupyter_output>Best Score: 0.7082328462666098
Best Hyperparameters: {'n_estimators': 250, 'min_samples_split': 32, 'min_samples_leaf': 9, 'max_depth': 5}<jupyter_text>Gradient Boosting<jupyter_code>def hyperparameters_gb(data):
    """
    hyperparameters_gb: Encuentra los mejores hiperparametros para el algoritmo de gradient
                        boosting del conjunto de datos.
                        
    data: Conjunto de datos
    
    Return
    ------
    None    
    """

    data = data.sample(frac=0.2, random_state=4444)
    
    data = data.to_numpy()

    # Separar los datos de la etiqueta
    X, y = data[:, :-1], data[:, -1]

    # define el modelo
    clf = GradientBoostingClassifier()

    # define evaluation
    cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=4444)

    # define search space
    space = dict()
    space['n_estimators'] = list(range(100, 300, 30))
    space['loss'] = ['deviance', 'exponential']
    space['max_depth'] = list(range(5, 100, 10))
    space['min_samples_split'] = list(range(2, 40, 5))
    space['min_samples_leaf'] = list(range(1, 12, 2))

    search = RandomizedSearchCV(clf, space, n_iter=100,
                                scoring='accuracy', n_jobs=-1, cv=cv,
                                random_state=4444)

    # execute search
    result = search.fit(X, y)
    # summarize result
    print('Best Score: %s' % result.best_score_)
    print('Best Hyperparameters: %s' % result.best_params_)

    return None
best_param_gb = hyperparameters_gb(final_data)<jupyter_output>Best Score: 0.6920357497517379
Best Hyperparameters: {'n_estimators': 130, 'min_samples_split': 32, 'min_samples_leaf': 3, 'max_depth': 5, 'loss': 'exponential'}<jupyter_text>AdaBoost<jupyter_code>def hyperparameters_ab(data):
    """
    hyperparameters_ab: Encuentra los mejores hiperparametros para el algoritmo de adaboost
                        del conjunto de datos.
                        
    data: Conjunto de datos
    
    Return
    ------
    None    
    """

    data = data.sample(frac=0.2, random_state=4444)
    
    data = data.to_numpy()

    # Separar los datos de la etiqueta
    X, y = data[:, :-1], data[:, -1]

    # define el modelo
    clf = AdaBoostClassifier()

    # define evaluation
    cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)

    # define search space
    space = dict()
    space['n_estimators'] = list(range(50, 500, 30))

    search = RandomizedSearchCV(clf, space, n_iter=100,
                                scoring='accuracy', n_jobs=-1, cv=cv,
                                random_state=4444)

    # execute search
    result = search.fit(X, y)
    # summarize result
    print('Best Score: %s' % result.best_score_)
    print('Best Hyperparameters: %s' % result.best_params_)

    return None
best_param_ab = hyperparameters_ab(final_data)<jupyter_output>/usr/local/lib/python3.6/dist-packages/sklearn/model_selection/_search.py:281: UserWarning: The total space of parameters 15 is smaller than n_iter=100. Running 15 iterations. For exhaustive searches, use GridSearchCV.
  % (grid_size, self.n_iter, grid_size), UserWarning)<jupyter_text>LightGBM<jupyter_code>def hyperparameters_lgb(data):
    """
    hyperparameters_lgb: Encuentra los mejores hiperparametros para el algoritmo de LightGBM
                         del conjunto de datos.
                        
    data: Conjunto de datos
    
    Return
    ------
    None    
    """

    data = data.sample(frac=0.2, random_state=4444)
    
    data = data.to_numpy()

    # Separar los datos de la etiqueta
    X, y = data[:, :-1], data[:, -1]

    # define el modelo
    clf = LGBMClassifier()

    # define evaluation
    cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=4444)

    # define search space
    space = dict()
    #space['objective'] = 'binary'
    #space['metric'] = 'binary_logloss'
    space['subsample'] = [0.8]
    space['n_estimators'] = [100, 500, 1000, 3000, 5000]
    space['learning_rate'] = [0.0001, 0.001, 0.01, 0.1, 1.0]
    space['max_depth'] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    space['num_leaves'] = [2, 4, 8, 16, 32, 64, 128, 256, 512]
    space['boosting_type'] = ['gbdt', 'dart', 'goss']

    search = RandomizedSearchCV(clf, space, n_iter=100,
                                scoring='accuracy', n_jobs=-1, cv=cv,
                                random_state=4444)

    # execute search
    result = search.fit(X, y)
    # summarize result
    print('Best Score: %s' % result.best_score_)
    print('Best Hyperparameters: %s' % result.best_params_)

    return None
best_param_lgb = hyperparameters_lgb(final_data)<jupyter_output>Best Score: 0.7072331772828299
Best Hyperparameters: {'subsample': 0.8, 'num_leaves': 8, 'n_estimators': 500, 'max_depth': 7, 'learning_rate': 0.01, 'boosting_type': 'goss'}<jupyter_text>A continuación, se utilizará los resultados anteriores para Voting Classifier. Para ello, se calibra cada uno de los clasificadores con  [Isotonic](https://scikit-learn.org/stable/modules/generated/sklearn.calibration.CalibratedClassifierCV.html)**CalibratedClassifierCV**: Es un calibrador de probabilidad con regresión isotónica o regresión logística.<jupyter_code>kfold = KFold(n_splits=10, shuffle=True, random_state=4444)

clf_VC1 = RandomForestClassifier(n_estimators=250, min_samples_split=32,
                                 min_samples_leaf=9, max_depth=5,
                                 random_state=4444)

clf_VC2 = GradientBoostingClassifier(n_estimators=130, min_samples_split=32,
                                     min_samples_leaf=3, max_depth=5,
                                     loss = 'exponential', random_state=4444)

clf_VC3 = AdaBoostClassifier(n_estimators=80, random_state=4444)

clf_VC4 = LGBMClassifier(n_estimators = 500, max_depth = 7, num_leaves = 8,
                         learning_rate = 0.01, boosting_type = 'gbdt',
                         subsample=0.8, random_state=4444)

rf_isotonic = CalibratedClassifierCV(clf_VC1, method='isotonic', cv=kfold)
gb_isotonic = CalibratedClassifierCV(clf_VC2, method='isotonic', cv=kfold)
ad_isotonic = CalibratedClassifierCV(clf_VC3, method='isotonic', cv=kfold)
lgb_isotonic = CalibratedClassifierCV(clf_VC4, method='isotonic', cv=kfold)<jupyter_output><empty_output><jupyter_text>Ahora bien, se implementa el nuevo Voting Classifier con los resultados de los modelos calibrados<jupyter_code>vc_isotonic = VotingClassifier(estimators=[('rf',rf_isotonic), ('gb',gb_isotonic),
                                     ('ab', ad_isotonic), ('lgb', lgb_isotonic)],
                                                             voting='soft', weights=None)
vc_isotonic.fit(X_train,y_train)
models = {"Voting Classifier": vc_isotonic, "Randon Forest": rf_isotonic, 
          "Gradient Boosting":gb_isotonic, "AdaBoost":ad_isotonic, 
          "LightGBM":lgb_isotonic}
#Resultados de las métricas de Voting classifer
y_pred_VC = vc_isotonic.predict(X_test)

accuracy_VC_iso = accuracy_score(y_test, y_pred_VC)
precision_VC_iso = precision_score(y_test, y_pred_VC, average='weighted')
recall_VC_iso = recall_score(y_test, y_pred_VC, average='weighted')
f1_VC_iso = f1_score(y_test, y_pred_VC, average='weighted')

print("accuracy:", accuracy_VC_iso)
print("Precision:", precision_VC_iso)
print("Recall:", recall_VC_iso)
print('f1_score:',f1_VC_iso)
# #Resultados de las métricas de Random Forest
rf_isotonic.fit(X_train,y_train)

y_predrf2 = rf_isotonic.predict(X_test)

accuracy_rf2 = accuracy_score(y_test, y_predrf2)
precision_rf2 = precision_score(y_test, y_predrf2, average='weighted')
recall_rf2 = recall_score(y_test, y_predrf2, average='weighted')
f1_rf2 = f1_score(y_test, y_predrf2, average='weighted')
print("accuracy:", accuracy_rf2)
print("Precision:", precision_rf2)
print("Recall:", recall_rf2)
print('f1_score:', f1_rf2)
#Resultados de las métricas de Gradient Boosting
gb_isotonic.fit(X_train,y_train)

y_predgb2 = gb_isotonic.predict(X_test)

accuracy_gb2 = accuracy_score(y_test, y_predgb2)
precision_gb2 = precision_score(y_test, y_predgb2, average='weighted')
recall_gb2 = recall_score(y_test, y_predgb2, average='weighted')
f1_gb2 = f1_score(y_test, y_predgb2, average='weighted')
print("accuracy:", accuracy_gb2)
print("Precision:", precision_gb2)
print("Recall:", recall_gb2)
print('f1_score:',f1_gb2)
#Resultados de las métricas de AdaBoost
ad_isotonic.fit(X_train,y_train)

y_predad2 = ad_isotonic.predict(X_test)

accuracy_ad2 = accuracy_score(y_test, y_predad2)
precision_ad2 = precision_score(y_test, y_predad2, average='weighted')
recall_ad2 = recall_score(y_test, y_predad2, average='weighted')
f1_ad2 = f1_score(y_test,y_predad2, average='weighted')
print("accuracy:", accuracy_ad2)
print("Precision:", precision_ad2)
print("Recall:", recall_ad2)
print('f1_score:',f1_ad2)
#Resultados de las métricas de LigthGBM
lgb_isotonic.fit(X_train,y_train)

y_predlgb2 = lgb_isotonic.predict(X_test)

accuracy_lgb2 = accuracy_score(y_test, y_predlgb2)
precision_lgb2 = precision_score(y_test, y_predlgb2, average='weighted')
recall_lgb2 = recall_score(y_test, y_predlgb2, average='weighted')
f1_lgb2 = f1_score(y_test, y_predlgb2, average='weighted')
print("accuracy:", accuracy_lgb2)
print("Precision:", precision_lgb2)
print("Recall:", recall_lgb2)
print('f1_score:', f1_lgb2)<jupyter_output>accuracy: 0.7100456621004566
Precision: 0.7162173763736264
Recall: 0.7100456621004566
f1_score: 0.7079616747604671<jupyter_text>EvaluaciónSe realiza una evaluación estratificada con una validación cruzada. A continuación se observa un esquema que explica el procedimiento que se ha llevado a acabo en este estudio. Gradient Boosting<jupyter_code>kfold = KFold(n_splits=10, shuffle=True, random_state=4444)

X, y = split_data[:, :-1], split_data[:, -1]
# Accuracy
scores = cross_val_score(gb_isotonic, X, y, cv=kfold)
scores.mean()
# f1 score
scores1 = cross_val_score(gb_isotonic, X, y, cv=kfold, scoring='f1_weighted')
scores1.mean()
# Precision
scores2 = cross_val_score(gb_isotonic, X, y, cv=kfold, scoring='precision_weighted')
scores2.mean()
# Recall
scores3 = cross_val_score(gb_isotonic, X, y, cv=kfold, scoring='recall_weighted')
scores3.mean()
#corss validated final results of tuned Gradient Boosting
print("Accuracy:",scores.mean())
print("Precision:",scores2.mean())
print("Recall:",scores3.mean())
print("F1:",scores1.mean())
all_scores=[]
all_scores.append(scores)
all_scores.append(scores2)
all_scores.append(scores3)
all_scores.append(scores1)

all_scores = pd.DataFrame({'Accuracy': scores, 'Precision': scores2, 
                           'Recall': scores3, 'F1score':scores1})
#all_scores
all_scores.to_csv('result_gb.csv')
all_scores = pd.read_csv('result_gb.csv')
all_scores.drop(['Unnamed: 0'], axis=1, inplace=True)
all_scores<jupyter_output><empty_output><jupyter_text>Visualización de las métricas<jupyter_code>ax = sns.boxplot(x="variable", y="value", data=pd.melt(all_scores), palette=("RdBu_r"), linewidth=2.0, width=0.6)
ax.set_title("Métricas de evaluación Gradient Boosting")

plt.show()<jupyter_output><empty_output><jupyter_text>Voting Clasifier<jupyter_code># Accuracy
scores4 = cross_val_score(vc_isotonic, X, y, cv=kfold)
scores4.mean()
# f1 score
scores5 = cross_val_score(vc_isotonic, X, y, cv=kfold, scoring='f1_weighted')
scores5.mean()
# Precision
scores6 = cross_val_score(vc_isotonic, X, y, cv=kfold, scoring='precision_weighted')
scores6.mean()
# Recall
scores7 = cross_val_score(vc_isotonic, X, y, cv=kfold, scoring='recall_weighted')
scores7.mean()
#corss validated final results of tuned Gradient Boosting
print("Accuracy:",scores4.mean())
print("Precision:",scores6.mean())
print("Recall:",scores7.mean())
print("F1:",scores5.mean())
all_scores=[]
all_scores.append(scores4)
all_scores.append(scores6)
all_scores.append(scores7)
all_scores.append(scores5)

all_scores = pd.DataFrame({'Accuracy': scores4, 'Precision': scores6, 
                           'Recall': scores7, 'F1score':scores5})
all_scores
all_scores.to_csv('result_VC.csv')
all_scores = pd.read_csv('result_VC.csv')
all_scores.drop(['Unnamed: 0'], axis=1, inplace=True)
all_scores
ax = sns.boxplot(x="variable", y="value", data=pd.melt(all_scores), palette=("RdBu_r"), linewidth=2.0, width=0.6)
ax.set_title("Métricas de evaluación Voting Clasifier")

plt.show()<jupyter_output><empty_output><jupyter_text>Randon Forest<jupyter_code># Accuracy
scores8 = cross_val_score(rf_isotonic, X, y, cv=kfold)
scores8.mean()
# f1 score
scores9 = cross_val_score(rf_isotonic, X, y, cv=kfold, scoring='f1_weighted')
scores9.mean()
# Precision
scores10 = cross_val_score(rf_isotonic, X, y, cv=kfold, scoring='precision_weighted')
scores10.mean()
# Recall
scores11 = cross_val_score(rf_isotonic, X, y, cv=kfold, scoring='recall_weighted')
scores11.mean()
#corss validated final results of tuned Gradient Boosting
print("Accuracy:",scores8.mean())
print("Precision:",scores10.mean())
print("Recall:",scores11.mean())
print("F1:",scores9.mean())
all_scores=[]
all_scores.append(scores8)
all_scores.append(scores10)
all_scores.append(scores11)
all_scores.append(scores9)

all_scores = pd.DataFrame({'Accuracy': scores8, 'Precision': scores10, 
                           'Recall': scores11, 'F1score':scores9})
all_scores
all_scores.to_csv('result_rf.csv')
all_scores = pd.read_csv('result_rf.csv')
all_scores.drop(['Unnamed: 0'], axis=1, inplace=True)
all_scores
ax = sns.boxplot(x="variable", y="value", data=pd.melt(all_scores), palette=("RdBu_r"), linewidth=2.0, width=0.6)
ax.set_title("Métricas de evaluación Random Forest")

plt.show()<jupyter_output><empty_output><jupyter_text>LightGBM<jupyter_code># Accuracy
scores12 = cross_val_score(lgb_isotonic, X, y, cv=kfold)
scores12.mean()
# f1 score
scores13 = cross_val_score(lgb_isotonic, X, y, cv=kfold, scoring='f1_weighted')
scores13.mean()
# Precision
scores14 = cross_val_score(lgb_isotonic, X, y, cv=kfold, scoring='precision_weighted')
scores14.mean()
# Recall
scores15 = cross_val_score(lgb_isotonic, X, y, cv=kfold, scoring='recall_weighted')
scores15.mean()
#corss validated final results of tuned Gradient Boosting
print("Accuracy:",scores12.mean())
print("Precision:",scores14.mean())
print("Recall:",scores15.mean())
print("F1:",scores13.mean())
all_scores=[]
all_scores.append(scores12)
all_scores.append(scores14)
all_scores.append(scores15)
all_scores.append(scores13)

all_scores = pd.DataFrame({'Accuracy': scores12, 'Precision': scores14, 
                           'Recall': scores15, 'F1score':scores13})
all_scores
all_scores.to_csv('result_lgb.csv')
all_scores = pd.read_csv('result_lgb.csv')
all_scores.drop(['Unnamed: 0'], axis=1, inplace=True)
all_scores
ax = sns.boxplot(x="variable", y="value", data=pd.melt(all_scores), palette=("RdBu_r"), linewidth=2.0, width=0.6)
ax.set_title("Métricas de evaluación LightGBM")

plt.show()<jupyter_output><empty_output><jupyter_text>Curvas ROC<jupyter_code>def roc_model(models, X_train, X_test, y_train, y_test):
    """
    roc_model: Realiza un solo gráfico con cada una de las curvas ROC de los modelos
               implementados en el estudio
    
    Return
    ------
    None    
    """
    
    # Generar una predicción sin habilidad (clase mayoritaria)
    ns_probs = [0 for _ in range(len(y_test))]

    # Modelos 
    voting_c = list(models.values())[0]
    rf_m = list(models.values())[1]
    gb_m = list(models.values())[2]
    ad_m = list(models.values())[3]
    lgb_m = list(models.values())[4]
    
    # Ajustar los modelos
    voting_c.fit(X_train, y_train)
    rf_m.fit(X_train, y_train)
    gb_m.fit(X_train, y_train)
    ad_m.fit(X_train, y_train)
    lgb_m.fit(X_train, y_train)

    # Predecir las probabilidades
    voting_c_probs = voting_c.predict_proba(X_test)
    rf_m_probs = rf_m.predict_proba(X_test)
    gb_m_probs = gb_m.predict_proba(X_test)
    ad_m_probs = ad_m.predict_proba(X_test)
    lgb_m_probs = lgb_m.predict_proba(X_test)

    # Mantener las probabilidades para el resultado positivo solamente
    voting_c_probs = voting_c_probs[:, 1]
    rf_m_probs = rf_m_probs[:, 1]
    gb_m_probs = gb_m_probs[:, 1]
    ad_m_probs = ad_m_probs[:, 1]
    lgb_m_probs = lgb_m_probs[:, 1]
    

    ns_auc = roc_auc_score(y_test, ns_probs)
    auc_voting = roc_auc_score(y_test, voting_c_probs)
    auc_rf = roc_auc_score(y_test, rf_m_probs)
    auc_gb = roc_auc_score(y_test, gb_m_probs)
    auc_ad = roc_auc_score(y_test, ad_m_probs)
    auc_lgb = roc_auc_score(y_test, lgb_m_probs)

    # Resumen de los scores
    print(f'No Skill: ROC AUC={round(ns_auc, 3)}')
    print(f'{list(models.keys())[0]}: ROC AUC = {round(auc_voting, 3)}')
    print(f'{list(models.keys())[1]}: ROC AUC = {round(auc_rf, 3)}')
    print(f'{list(models.keys())[2]}: ROC AUC = {round(auc_gb, 3)}')
    print(f'{list(models.keys())[3]}: ROC AUC = {round(auc_ad, 3)}')
    print(f'{list(models.keys())[4]}: ROC AUC = {round(auc_lgb, 3)}')

    # Calcular la curva roc
    ns_fpr, ns_tpr, _ = roc_curve(y_test, ns_probs)
    vc_fpr, vc_tpr, _ = roc_curve(y_test, voting_c_probs)
    rf_fpr, rf_tpr, _ = roc_curve(y_test, rf_m_probs)
    gb_fpr, gb_tpr, _ = roc_curve(y_test, gb_m_probs)
    ad_fpr, ad_tpr, _ = roc_curve(y_test, ad_m_probs)
    lgb_fpr, lgb_tpr, _ = roc_curve(y_test, lgb_m_probs)
    
    # Graficar las curva ROC de cada modelo
    plt.plot(ns_fpr, ns_tpr, linestyle='--', label= f'No Skill: AUROC = {round(ns_auc, 3)}')
    plt.plot(vc_fpr, vc_tpr, linestyle='--', label=f'Voting Classifier: AUROC = {round(auc_voting, 3)}')
    plt.plot(rf_fpr, rf_tpr, linestyle='-.', label=f'Random Forest: AUROC = {round(auc_rf, 3)}')
    plt.plot(gb_fpr, gb_tpr, linestyle=':', label=f'Gradient Boosting: AUROC = {round(auc_gb, 3)}')
    plt.plot(ad_fpr, ad_tpr, linestyle='-', label=f'AdaBoost: AUROC = {round(auc_ad, 3)}')
    plt.plot(lgb_fpr, lgb_tpr, linestyle='--', label=f'LigthGBM: AUROC = {round(auc_lgb, 3)}')
    
    # Titulo
    plt.title('ROC Plot')

    # axis labels
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    
    # Mostrar etiquetas
    plt.legend()
    
    # Mostrar grafico
    plt.show()
    
    return None
# Graficar todos modelos
roc_model(models, X_train, X_test, y_train, y_test)<jupyter_output>No Skill: ROC AUC=0.5
Voting Classifier: ROC AUC = 0.782
Randon Forest: ROC AUC = 0.779
Gradient Boosting: ROC AUC = 0.776
AdaBoost: ROC AUC = 0.76
LightGBM: ROC AUC = 0.783
{'fraction_non_alphanumeric': 0.12775308641975308, 'fraction_numerical': 0.03451851851851852, 'mean_word_length': 4.762805919180421, 'pattern_counts': {'":': 5, '<': 123, '<?xml version=': 0, '>': 123, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '33', 'dir': 'jupyter-structured-clean-dedup', 'id': '482751', 'license': 'MIT', 'n_tokens_mistral': 16267, 'n_tokens_neox': 15059, 'n_words': 2882, 'path': 'credit_risk_management.ipynb', 'repo_name': 'cbarros7/credit_risk_management', 'size': '40500'}