<jupyter_start><jupyter_text>Práctica 1 Resolución de problemas de clasificación y análisis experimental*<NAME>* El primer paso es leer los datos a analizar.<jupyter_code>import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
raw_data=pd.read_csv("mamografias.csv",na_values=["?", "N"])<jupyter_output><empty_output><jupyter_text>Y observar rápidamente la forma que tienen los datos:<jupyter_code>raw_data.head(100)
raw_data.info()
raw_data.describe()
raw_data['Shape'].count()<jupyter_output><empty_output><jupyter_text>A excepción de la edad, los estadísticos calculados no tienen sentido para las variables medidas (BI-RADS, Margin y Density son cuantitativas). Sí tiene algo de interés el número de elementos de cada clase (nos informa de los datos perdidos) y los cuantiles.  Le cambiamos el nombre a las columnas para que sean más sencillas de manipular.<jupyter_code>raw_data.columns = [col.lower() for col in raw_data]<jupyter_output><empty_output><jupyter_text>1. Preprocesamiento de los Datos Transformamos los atributos de tipo cadena en valores numéricos:<jupyter_code>from sklearn import preprocessing

le=preprocessing.LabelEncoder()

data=raw_data.copy()

#Codificamos la columna de la forma del tumor (necesario para la sustitución de valores perdidos)
indices = pd.notnull(data['shape'])
data.loc[indices, ('shape')] = le.fit_transform(raw_data.loc[indices, ('shape')])
data.describe()<jupyter_output><empty_output><jupyter_text>Valores perdidosAntes de entrenar modelos de predicción usando nuestro conjunto de datos es importante eliminar/sustituir los valores perdidos para poder pasar a los algoritmos de aprendizaje valores numéricos con los que este pueda trabajar. Si una columna está formada mayoritariamente por valores perdidos, esta se puede eliminar. La columna con más pérdidas en nuestro caso es "Density" con 76 pérdidas, menos de un 10%, lo que no es suficiente para eliminarla. Por otro lado, tampoco parece conveniente eliminar 76 filas completas de la tabla. Intentaremos, por tanto, sustituir estos valores de la forma más insesgada que encontremos.Sustituir los valores perdidos por la moda de su respectiva columna es realizable en columnas como BI-RADS y Age con ínfimas pérdidas. Para el resto de columnas, puede suponer un sesgo que es mejor evitar. Probaremos con el IterativeImputer de Scikit-Learn:https://scikit-learn.org/stable/modules/generated/sklearn.impute.IterativeImputer.htmlsklearn.impute.IterativeImputerEste método utliza valores flotantes, por lo que redondearemos el resultado para obtener un resultado válido en aquellas columnas que solo acepten valores enteros (todas).<jupyter_code>from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
imp = IterativeImputer(random_state=0, initial_strategy='most_frequent')
values = imp.fit_transform(data.values[:,0:5])
values = values.astype(int)
data = pd.DataFrame(values)
data.columns = raw_data.columns[0:5]
data = data.join(raw_data['severity'])
data<jupyter_output><empty_output><jupyter_text>Búsqueda de outliersComo estamos trabajando con datos categórigos, no podemos buscar outliers por el procedimiento estándar. Valores a predecir (severidad del tumor)Saber cuántos hay de cada uno nos permitirá intuir cuan buenos son nuestros modelos y nos será útil, en general, en la fase de análisis de resultados. Vamos a consultar esto en los datos originales (con etiquetas sin codificar)<jupyter_code>data['severity'].describe()<jupyter_output><empty_output><jupyter_text>Vemos que hay 961 tumores en total, de los cuales 516 (un 53.69%) son benignos. Esto implicará que, si asumimos que todos los tumores son benignos acertaremos un 53.69% de las veces. Este umbral a superar es bastante bajo, por lo que no debería ser difícil obtener resultados mejores.  Dependencia Vamos a generar un histograma que muestre la cantidad de tumores malignos y benignos encontrados en función del tipo de diagnóstico (BI-RAD).<jupyter_code>import seaborn as sns
sns.set(style="whitegrid", color_codes=True)
sns.set(rc={'figure.figsize':(11.7,8.27)})
sns.countplot('bi-rads', data=data, hue='severity')
sns.set(style="whitegrid", color_codes=True)
sns.set(rc={'figure.figsize':(18.7,5.27)})
sns.countplot('age', data=data, hue='severity')
sns.set(style="whitegrid", color_codes=True)
sns.set(rc={'figure.figsize':(11.7,5.27)})
#La columna 'shape' de data está codificada. La descodificamos
data['shape'] = le.inverse_transform( data['shape'] )
sns.countplot('shape', data=raw_data, hue='severity')
sns.set(style="whitegrid", color_codes=True)
sns.set(rc={'figure.figsize':(11.7,5.27)})
sns.countplot('margin', data=data, hue='severity')
sns.set(style="whitegrid", color_codes=True)
sns.set(rc={'figure.figsize':(11.7,5.27)})
sns.countplot('density', data=data, hue='severity')<jupyter_output><empty_output><jupyter_text>Análisis de componentes principalesQueremos ver si podemos considerar alguna de las variables como redundante. Usaremos el módulo para PCA (Principal Components Analysis) de Scikit-Learn:https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.htmlsklearn.decomposition.PCA<jupyter_code>from sklearn.decomposition import PCA
data['severity']=le.fit_transform(raw_data['severity'])
#Volvemos a codificar la columna de la forma del tumor (necesario para entrenar los modelos)
indices = pd.notnull(data['shape'])
le.fit( list(raw_data.loc[indices, ('shape')]) )
data['shape'] = le.transform(data['shape'])
pca = PCA()
pca.fit(data.values[:,0:5])
print("Componentes\n", pca.components_)
print("\nPeso por componente\n", pca.explained_variance_ratio_)
print("\nDatos originales\n", data)
print("\nDatos en componentes principales\n", pca.transform(data.values[:,0:5])[:,0:2])<jupyter_output>Componentes
 [[ 1.41921959e-02  9.98420612e-01 -3.13144990e-02  4.43629324e-02
   2.48921260e-03]
 [-1.60104721e-01  5.59142239e-02  5.87505733e-01 -7.90343090e-01
  -3.78799584e-02]
 [ 3.47975946e-03 -1.36866919e-03  8.03115242e-01  5.93930777e-01
   4.73091746e-02]
 [-9.84458643e-01  5.29213941e-03 -9.16012541e-02  1.34831925e-01
  -6.51362930e-02]
 [ 7.06691753e-02 -4.23764508e-05  2.17148274e-02  4.95612171e-02
  -9.96031133e-01]]

Peso por componente
 [9.81290006e-01 1.38315225e-02 2.16787483e-03 1.83408888e-03
 8.76507512e-04]

Datos originales
      bi-rads  age  shape  margin  density  severity
0          5   67      1       5        3         1
1          4   43      3       1        2         1
2          5   58      0       5        3         1
3          4   28      3       1        3         0
4          5   74      3       5        2         1
..       ...  ...    ...     ...      ...       ...
956        4   47      2       1        3         0
957        4   56      0  [...]<jupyter_text>Vemos que basta con tomar las dos primeras componentes (explican más del 99% de la información del dataset).<jupyter_code>t_data = pca.transform(data.values[:,0:5])[:,0:2]
#Separamos los tumores benignos con coordenadas en este espacio de dimensión reducida...
x_b = [d[1] for i,d in enumerate(t_data) if raw_data.values[i,5]=='benigno']
y_b = [d[0] for i,d in enumerate(t_data) if raw_data.values[i,5]=='benigno']
#... de los tumores malignos...
x_m = [d[1] for i,d in enumerate(t_data) if raw_data.values[i,5]=='maligno']
y_m = [d[0] for i,d in enumerate(t_data) if raw_data.values[i,5]=='maligno']
#... y los visualizamos
sns.set(rc={'figure.figsize':(11.7,8.27)})
plt.plot(x_b, y_b, 'b.', x_m, y_m, 'r.')<jupyter_output><empty_output><jupyter_text>Observamos una separación relativamente clara de ambas clases, pero también que existe una superposición de ambas que será muy difícil de eliminar.  Análisis FactorialQueremos ver si podemos reducir la dimensión del dataset con análisis factorial.https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.FactorAnalysis.htmlsklearn.decomposition.FactorAnalysis<jupyter_code>from sklearn.decomposition import FactorAnalysis
fa = FactorAnalysis()
fa.fit(data.values[:,0:5])
print("Componentes\n", fa.components_)
print("\Varianza por componente\n", fa.noise_variance_)
print("\nDatos originales\n", data)
print("\nDatos factorizados\n", fa.transform(data.values[:,0:5])[:,0:5])
f_data = fa.transform(data.values[:,0:5])
f_data<jupyter_output><empty_output><jupyter_text>Selección de característicasTratamos de encontrar las mejores cararcterísticas aplicando tests estadísticos univariables. Usamos el módulo SelectKBest de Scikit-Learn con el test de $\chi^2$.<jupyter_code>from sklearn.feature_selection import SelectKBest<jupyter_output><empty_output><jupyter_text>Método de $\chi^2$<jupyter_code>from sklearn.feature_selection import chi2
charact = data.values[:,0:5]
label = data.values[:,5]
reducer = SelectKBest(chi2, k='all').fit(charact, label)
reducer.scores_<jupyter_output><empty_output><jupyter_text>El selector de características de Scikit nos dice que la propiedad Density cuenta con una puntuación como característica muy baja. El código BI-RADS tampoco tiene una puntuación muy alta. Tendremos esto en cuenta en la fase de entrenamiento de los modelos.<jupyter_code>reducer = SelectKBest(chi2, k=3).fit(charact, label)
#Características con mayor puntuación
reducer.transform(charact)<jupyter_output><empty_output><jupyter_text>OneHot Encoding<jupyter_code>from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
categorical_features = ['bi-rads', 'shape', 'margin', 'density']
categorical_transformer = Pipeline(steps=[('onehot', OneHotEncoder())])

ohe = ColumnTransformer(transformers=[('cat', categorical_transformer, categorical_features)])

char_columns = ['bi-rads', 'age', 'shape', 'margin', 'density']
onehot_char = ohe.fit_transform(data[char_columns]).toarray()
onehot_char<jupyter_output><empty_output><jupyter_text>2. Entrenamiento de los modelosSe usarán cinco modelos predictivos distintos. Dado el tipo de problema que estamos enfrentando, se buscarán técnicas que traten de maximizar dos métricas distintas: - **La interpretabilidad del modelo.** En el ámbito del estudio de una enfermedad nueva o con comportamientos desconocidos, puede ser de gran interés para la comunidad científica encontrar, por medio de la computación, métodos directos para clasificar la enfermedad de un paciente en base a sus síntomas. Para esto, un modelo interpretable da mucha más información útil para posterior investigación.- **La fiabilidad de sus resultados.** En caso de que los resultados de aquellos modelos interpretables no sean suficientemente buenos o no arrojen nueva información sobre el fenómeno estudiado, tiene sentido dar prioridad a aquellos métodos que resuelvan el problema de clasificación con un menor margen de error. Los modelos elegidos son el Naïve-Bayes, árboles de decisión, ...  Antes de entrenar los modelos debemos diseñar el método de entrenamiento y testeo. Usaremos validación cruzada de cinco particiones. Una opción es con cross_val_predict<jupyter_code>from sklearn.model_selection import cross_val_predict
from sklearn.metrics import confusion_matrix
#y_pred = cross_val_predict(clf, x, y, cv=5)
#conf_mat = confusion_matrix(y, y_pred)<jupyter_output><empty_output><jupyter_text>Función general que recibe un dataset y el target correspondientey el estimador a utilizar, y devuelve la matriz de confusión de aplicar una validación cruzada sobre el modelo generado.<jupyter_code>#reductor solo se usa si show_plot es True
def test_model(estimator, X, y, reductor=None, cv=5, show_plot=False):
  y_pred = cross_val_predict(estimator, X, y, cv=cv) 
  if show_plot:
    assert len(X.shape) == 2 or reductor != None
    red_data = reductor.transform(X)[:,0:2]
    
    """
    #Visualizamos los Aciertos
    x_a = [d[1] for i,d in enumerate(red_data) if y[i]==y_pred[i]]
    y_a = [d[0] for i,d in enumerate(red_data) if y[i]==y_pred[i]]
    plt.plot(x_a, y_a, 'g.', label='Aciertos')
    
    #Visualizamos los Fallos
    x_f = [d[1] for i,d in enumerate(red_data) if y[i]!=y_pred[i]]
    y_f = [d[0] for i,d in enumerate(red_data) if y[i]!=y_pred[i]]
    plt.plot(x_f, y_f, 'k.', label='Fallos')
    """

    #Visualizamos los clasificados en cada clase
    x_1 = [d[1] for i,d in enumerate(red_data) if y_pred[i]==1.0]
    y_1 = [d[0] for i,d in enumerate(red_data) if y_pred[i]==1.0]
    x_2 = [d[1] for i,d in enumerate(red_data) if y_pred[i]==0.0]
    y_2 = [d[0] for i,d in enumerate(red_data) if y_pred[i]==0.0]
    plt.plot(x_1, y_1, 'c.', x_2, y_2, 'y.')
  return confusion_matrix(y, y_pred)

#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives

def prec_from_conf_mat(conf_mat):
  return round( (conf_mat[0,0]+conf_mat[1,1])/np.sum(conf_mat), 4)

def auc_from_conf_mat(conf_mat):
  #True Positives / Positives
  TPR = conf_mat[1,1]/(conf_mat[1,1]+conf_mat[1,0])
  #False Positives / Negatives
  FPR = conf_mat[0,1]/(conf_mat[0,0]+conf_mat[0,1])
  return round( (1.0+TPR-FPR)/2.0, 4)

def f1_from_conf_mat(conf_mat):
  return round( 2*conf_mat[1,1]/(2*conf_mat[1,1]+conf_mat[0,1]+conf_mat[1,0]), 4)
#Parámetros: lista de estimadores, lista con sus respectivos nombres, 
#             conjuntos de características, vector de valores objetivo.
#Devuelve: un dataframe con el nombre, precisión, AUC y F-score de cada modelo generado usando cada estimador
def test_todos(estimadores, nombres, X, y):
  assert len(estimadores)==len(nombres)
  tabla = []
  for estim,nombre in zip(estimadores, nombres):
    conf_mat = test_model(estim, X, y)
    prec = prec_from_conf_mat(conf_mat)
    auc = auc_from_conf_mat(conf_mat)
    f1 = f1_from_conf_mat(conf_mat)
    tabla.append([prec, auc, f1])
  return pd.DataFrame(tabla, index=nombres, columns=['Precisión', 'AUC', 'F1-Score'])
def normalizar_dataset(data):
  minimo = min(data.ravel())
  maximo = max(data.ravel())
  rango = maximo-minimo
  return (data-minimo)/rango
char = data.values[:,0:5]
target = data.values[:,5]
red_char = reducer.transform(data.values[:,0:5])  #Reduced characteristics
norm_char = normalizar_dataset(char)<jupyter_output><empty_output><jupyter_text>**Naïve-Bayes**:<jupyter_code>from sklearn.naive_bayes import GaussianNB
conf_mat = test_model(GaussianNB(), char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(GaussianNB(), red_char, target)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[378 138]
 [ 70 375]]
Precisión: 0.7836
AUC: 0.7876
F1-Scores: 0.7829<jupyter_text>La precisión no ha mejorado usando las características seleccionadas.  Árbol de decisión (interpretable):<jupyter_code>from sklearn.tree import DecisionTreeClassifier
conf_mat = test_model(DecisionTreeClassifier(criterion='gini'), char, target, pca, show_plot=True)
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[414 102]
 [126 319]]
Precisión: 0.7627
AUC: 0.7596
F1-Scores: 0.7367<jupyter_text>Ahora lo testamos para varias profundidades máximas distintas:<jupyter_code>estimadores = [
               DecisionTreeClassifier(max_depth=None, random_state=1),
               DecisionTreeClassifier(max_depth=1, random_state=1),
               DecisionTreeClassifier(max_depth=2, random_state=1),
               DecisionTreeClassifier(max_depth=3, random_state=1),
               DecisionTreeClassifier(max_depth=4, random_state=1),
               DecisionTreeClassifier(max_depth=5, random_state=1)
]
nombres = [
           "Árbol completo",
           "Árbol p1",
           "Árbol p2",
           "Árbol p3",
           "Árbol p4",
           "Árbol p5"
]
result_arboles = test_todos(estimadores, nombres, char, target)
result_arboles.to_csv("arb_dec_comparados.csv")
#Visualizamos un árbol de profundidad 3 con 4/5 partes del dataset como entrenamiento
max_size = (np.size(char, axis=0)//5)*4
tree_clf = DecisionTreeClassifier(criterion='gini', max_depth=3)
tree_clf.fit(char[0:max_size, :], target[0:max_size])
import graphviz
from sklearn.tree import export_graphviz
# DOT data
dot_data = export_graphviz(tree_clf, out_file=None, 
                                filled=True)

# Draw graph
graph = graphviz.Source(dot_data, format="png")
graph.render('decision_tree') 
graph<jupyter_output><empty_output><jupyter_text>Visualizamos la clasificación hecha para una profundidad de 3 (la mejor obtenida)<jupyter_code>conf_mat = test_model(DecisionTreeClassifier(criterion='gini', max_depth=3), char, target, pca, show_plot=True)
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(DecisionTreeClassifier(criterion='gini', max_depth=3), norm_char, target, pca, show_plot=True)
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(DecisionTreeClassifier(criterion='gini', max_depth=3), red_char, target)
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(DecisionTreeClassifier(criterion='gini', max_depth=3), onehot_char, target)
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[416 100]
 [ 79 366]]
Precisión: 0.8137
AUC: 0.8143
F1-Scores: 0.8035<jupyter_text>**AdaBoost**<jupyter_code>from sklearn.ensemble import AdaBoostClassifier
conf_mat = test_model(AdaBoostClassifier(learning_rate=1, n_estimators=5), char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(AdaBoostClassifier(learning_rate=0.1, n_estimators=30), char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(AdaBoostClassifier(learning_rate=0.1, n_estimators=30), norm_char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(AdaBoostClassifier(learning_rate=0.1, n_estimators=30), red_char, target)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(AdaBoostClassifier(learning_rate=0.1, n_estimators=30), onehot_char, target)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[435  81]
 [101 344]]
Precisión: 0.8106
AUC: 0.808
F1-Scores: 0.7908<jupyter_text>Regresión Logística<jupyter_code>from sklearn.linear_model import LogisticRegression
conf_mat = test_model(LogisticRegression(random_state=1, C=1), char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(LogisticRegression(random_state=1, C=0.1), char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(LogisticRegression(random_state=1, C=0.1), norm_char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(LogisticRegression(random_state=1, C=0.1), red_char, target)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(LogisticRegression(random_state=1, C=0.1), onehot_char, target)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[427  89]
 [ 91 354]]
Precisión: 0.8127
AUC: 0.8115
F1-Scores: 0.7973<jupyter_text>Random Forest<jupyter_code>from sklearn.ensemble import RandomForestClassifier
conf_mat = test_model(RandomForestClassifier(random_state=1), char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[417  99]
 [101 344]]
Precisión: 0.7919
AUC: 0.7906
F1-Scores: 0.7748<jupyter_text>Ahora lo testamos para varias profundidades máximas distintas:<jupyter_code>estimadores = [
               RandomForestClassifier(max_depth=None, random_state=1),
               RandomForestClassifier(max_depth=1, random_state=1),
               RandomForestClassifier(max_depth=2, random_state=1),
               RandomForestClassifier(max_depth=3, random_state=1),
               RandomForestClassifier(max_depth=4, random_state=1),
               RandomForestClassifier(max_depth=5, random_state=1),
               RandomForestClassifier(max_depth=6, random_state=1),
               RandomForestClassifier(max_depth=7, random_state=1)
]
nombres = [
           "Árboles completos",
           "Árboles p1",
           "Árboles p2",
           "Árboles p3",
           "Árboles p4",
           "Árboles p5",
           "Árboles p6",
           "Árboles p7"
]
result_arboles = test_todos(estimadores, nombres, char, target)
result_arboles.to_csv("random_forest_comparacion.csv")
conf_mat = test_model(RandomForestClassifier(max_depth=4, random_state=1), char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(RandomForestClassifier(max_depth=4, random_state=1), red_char, target)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(RandomForestClassifier(max_depth=4, random_state=1), onehot_char, target)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[424  92]
 [ 83 362]]
Precisión: 0.8179
AUC: 0.8176
F1-Scores: 0.8053<jupyter_text>k-NN<jupyter_code>from sklearn.neighbors import KNeighborsClassifier
conf_mat = test_model(KNeighborsClassifier(5, metric='hamming', weights='uniform'), norm_char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[449  67]
 [114 331]]
Precisión: 0.8117
AUC: 0.807
F1-Scores: 0.7853<jupyter_text>Redes Neuronales<jupyter_code>from sklearn.neural_network import MLPClassifier
conf_mat = test_model(MLPClassifier(hidden_layer_sizes=(25, 3), max_iter=10000, random_state=1), char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(MLPClassifier(hidden_layer_sizes=(25, 3), max_iter=10000, random_state=1), norm_char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(MLPClassifier(hidden_layer_sizes=(25, 3), max_iter=10000, random_state=1), red_char, target)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(MLPClassifier(hidden_layer_sizes=(25, 3), max_iter=10000, random_state=1), onehot_char, target)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[415 101]
 [ 80 365]]
Precisión: 0.8117
AUC: 0.8122
F1-Scores: 0.8013<jupyter_text>SVM<jupyter_code>from sklearn.svm import LinearSVC
conf_mat = test_model(LinearSVC(random_state=1, max_iter=300000), char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(LinearSVC(random_state=1, C=0.1, max_iter=300000), norm_char, target, pca, show_plot=True)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(LinearSVC(random_state=1, max_iter=300000), red_char, target)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(LinearSVC(random_state=1, max_iter=300000), onehot_char, target)
#[0,0]-->True Negatives
#[0,1]-->False Positives
#[1,0]-->False Negatives
#[1,1]-->True Positives
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[440  76]
 [ 99 346]]
Precisión: 0.8179
AUC: 0.8151
F1-Scores: 0.7982<jupyter_text>Multiclasificador por Votación<jupyter_code>from sklearn.ensemble import VotingClassifier
clf1 = AdaBoostClassifier(learning_rate=0.1, n_estimators=30, random_state=1)
clf2 = LogisticRegression(random_state=1, C=0.1)
clf3 = RandomForestClassifier(max_depth=4, random_state=1)
eclf = VotingClassifier( estimators=[('ad', clf1), ('lr', clf2), ('rf', clf3)] )
conf_mat = test_model(eclf, char, target, pca, show_plot=True)
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(eclf, norm_char, target, pca, show_plot=True)
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(eclf, red_char, target)
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))
conf_mat = test_model(eclf, onehot_char, target)
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[424  92]
 [ 84 361]]
Precisión: 0.8169
AUC: 0.8165
F1-Scores: 0.804<jupyter_text>3. Test completo de cada modeloVamos a ejecutar cada modelo de los elegidos una serie de veces y quedarnos con un valor medio para cada métrica de las que estamos utilizando (precisión, AUC y F1-score) Vamos a probar los resultados de los siguientes modelos:  - Árbol de decisión- Random Forest- AdaBoost- Regresión Logística- Red Neuronal- SVM- Multiclasificador por Votación Testearemos los modelos elegidos con el dataset completo, con el dataset completo normalizado y con el dataset reducido por PCA.<jupyter_code>main_seed = 1
n_reps = 5

nombres = [
              'Árbol de Decisión',
              'Random Forest',
              'AdaBoost',
              'Regresión Logística',
              'Red Neuronal',
              'SVM Lineal',
              'MultiClas por Votación'
      ]

#Se generan tantas semillas como veces se vayan a repetir las cuentas
np.random.seed(main_seed)
semillas = np.random.randint(0, 1000000, n_reps)  
#Se crea una dataframe con las dimensiones del resultado
resultados = pd.DataFrame(0, index=nombres, columns=['Precisión', 'AUC', 'F1-Score'])
resultados_norm = pd.DataFrame(0, index=nombres, columns=['Precisión', 'AUC', 'F1-Score'])
resultados_red = pd.DataFrame(0, index=nombres, columns=['Precisión', 'AUC', 'F1-Score'])

#Se repite el experimento varias veces
for sem in semillas:

  clf1 = RandomForestClassifier(random_state=sem, max_depth=4)
  clf2 = AdaBoostClassifier(learning_rate=0.1, n_estimators=30, random_state=sem)
  clf3 = LogisticRegression(random_state=sem, C=0.1)
  estimadores = [
                DecisionTreeClassifier(random_state=sem, max_depth=3),
                clf1,
                clf2,
                clf3,
                MLPClassifier(hidden_layer_sizes=(25, 3), max_iter=10000, random_state=sem),
                LinearSVC(random_state=sem, max_iter=300000),
                VotingClassifier([('rf', clf1), ('ab', clf2), ('lr', clf3)])
    ]
  #Sumamos el dataframe resultado al actual
  resultados += test_todos(estimadores, nombres, char, target) 
  resultados_norm += test_todos(estimadores, nombres, norm_char, target)
  resultados_red += test_todos(estimadores, nombres, red_char, target)

#Tras sumar todos los resultados, dividimos entre el número de repeticiones
resultados /= n_reps
resultados_norm /= n_reps
resultados_red /= n_reps
resultados.to_csv("resultados.csv")
resultados
resultados_norm.to_csv("resultados_norm.csv")
resultados_norm
resultados_red.to_csv("resultados_red.csv")
resultados_red<jupyter_output><empty_output><jupyter_text>4. Procesado alternativo: codificación binariaLa mayor parte de las variables en este estudio no son cuantitativas sino, como ya se ha mencionado anteriormente, cualitivas. Esto hace que la segmentación espacial que llevan a cabo muchos de los algoritmos utilizados no tengan sentido, porque no existe ningún orden entre los valores de cada categoría. Como codificación alternativa se ha probado a transformar el valor de cada variable en un array binario (one-hot array) con el módulo OneHotEncoder de sklearn.<jupyter_code>from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.svm import LinearSVC
from sklearn.ensemble import VotingClassifier
main_seed = 1
n_reps = 4

nombres = [
              'Árbol de Decisión',
              'Random Forest',
              'AdaBoost',
              'Regresión Logística',
              'Red Neuronal',
              'SVM Lineal',
              'MultiClas por Votación'
      ]

#Se generan tantas semillas como veces se vayan a repetir las cuentas
np.random.seed(main_seed)
semillas = np.random.randint(0, 1000000, n_reps)  
#Se crea una dataframe con las dimensiones del resultado
resultados_onehot = pd.DataFrame(0, index=nombres, columns=['Precisión', 'AUC', 'F1-Score'])

#Se repite el experimento varias veces
for sem in semillas:

  clf1 = RandomForestClassifier(random_state=sem, max_depth=4)
  clf2 = AdaBoostClassifier(learning_rate=0.1, n_estimators=30, random_state=sem)
  clf3 = LogisticRegression(random_state=sem, C=0.1)
  estimadores = [
                DecisionTreeClassifier(random_state=sem, max_depth=3),
                clf1,
                clf2,
                clf3,
                MLPClassifier(hidden_layer_sizes=(25, 3), max_iter=10000, random_state=sem),
                LinearSVC(random_state=sem, max_iter=300000),
                VotingClassifier([('rf', clf1), ('ab', clf2), ('lr', clf3)])
    ]
  #Sumamos el dataframe resultado al actual
  resultados_onehot += test_todos(estimadores, nombres, onehot_char, target) 

#Tras sumar todos los resultados, dividimos entre el número de repeticiones
resultados_onehot /= n_reps
resultados_onehot.to_csv("resultados_onehot.csv")
resultados_onehot
main_seed = 1
n_reps = 5

nombres = [
              '<NAME>',
              '<NAME>',
      ]

#Se generan tantas semillas como veces se vayan a repetir las cuentas
np.random.seed(main_seed)
semillas = np.random.randint(0, 1000000, n_reps)  
#Se crea una dataframe con las dimensiones del resultado
resultados_trees_onehot = pd.DataFrame(0, index=nombres, columns=['Precisión', 'AUC', 'F1-Score'])

#Se repite el experimento varias veces
for sem in semillas:
  estimadores = [
                DecisionTreeClassifier(random_state=sem, max_depth=3),
                RandomForestClassifier(random_state=sem, max_depth=4)
    ]
  #Sumamos el dataframe resultado al actual
  resultados_trees_onehot += test_todos(estimadores, nombres, onehot_char, target) 

#Tras sumar todos los resultados, dividimos entre el número de repeticiones
resultados_trees_onehot /= n_reps
resultados_trees_onehot.to_csv("resultados_trees_onehot.csv")
resultados_trees_onehot
#Visualizamos un árbol de profundidad 3 con 4/5 partes del dataset como entrenamiento
total_size = np.size(char, axis=0)
max_size = (total_size//5)*4
part_size = total_size-max_size
tree_clf = DecisionTreeClassifier(max_depth=3, random_state=87)
tree_clf.fit(onehot_char[part_size:total_size, :], target[part_size:total_size])
import graphviz
from sklearn.tree import export_graphviz
# DOT data
dot_data = export_graphviz(tree_clf, out_file=None, 
                                filled=True)

# Draw graph
graph = graphviz.Source(dot_data, format="png")
graph.render('decision_tree_oneshot') 
graph
conf_mat = test_model(tree_clf, onehot_char, target)
print(conf_mat)
print("Precisión:", prec_from_conf_mat(conf_mat))
print("AUC:", auc_from_conf_mat(conf_mat))
print("F1-Scores:", f1_from_conf_mat(conf_mat))<jupyter_output>[[416 100]
 [ 79 366]]
Precisión: 0.8137
AUC: 0.8143
F1-Scores: 0.8035
{'fraction_non_alphanumeric': 0.1289695043428227, 'fraction_numerical': 0.03970189330629915, 'mean_word_length': 5.830993823694554, 'pattern_counts': {'":': 0, '<': 111, '<?xml version=': 0, '>': 215, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '30', 'dir': 'jupyter-structured-clean-dedup', 'id': '542550', 'license': 'MIT', 'n_tokens_mistral': 14457, 'n_tokens_neox': 13717, 'n_words': 2885, 'path': 'P1/P1-Alonso-Membrilla-Alejandro.ipynb', 'repo_name': 'aalonso99/Inteligencia-de-Negocio', 'size': '36535'}