Modelo de Clasificacion
DataSet seleccionado: Titanic (descargar)
*******************************************************************
1RA PARTE DE EXPO
*******************************************************************
Atributos
Variable Descripcion Detalles
Survival Clase deseada No (0) Yes (1)
Pclass Passanger Class
Name First and Last Name
Sex Sexo Female, Male
Age Age
Sibsp Number of siblings/spouses aboard
Parch Number of Parents/Children Aboard
Ticket Ticket Number
Fare Passenger Fare
Cabin Cabin
Embarked Por of Embarkation Cherbourg (C), Queenstown (Q),
Southampton (S)
Antes de empezar el modelado del clasificador, es importante analizar la data y realizar un
preprocesamiento.
Para empezar, demos un vistazo general e imprimamos los TOP 5 elementos
En este ejemplo ya se pueden ver de antemano que la variable Cabin posee algunos datos marcados
como NaN, es decir son atributos faltantes.
Podemos observar algunas variables que contienen datos en texto (Name, Sex, Ticket) e incluso se
identifica una variable que no aportara nada a nuestro modelo ya que es un contador y no es relevante
en este caso (PassengerId).
Ya desde el 1er análisis se identifica que SI debemos preprocesar la data, entonces miremos a mas
detalle el dataset.
1. PREPROCESAMIENTO DE DATOS
Este es el primer paso que se realiza en los modelos y es de vital importancia. El grafico mostrado a
continuación muestra un esquema general de los pasos que podemos seguir para hacer la limpieza de
los datos
Referencia: https://www.analyticsvidhya.com/blog/2021/06/data-cleaning-using-pandas/
*******************************************************************
2DA PARTE DE EXPO
*******************************************************************
MISSING VALUES
En un primer momento determinamos que en la variable Cabin faltaban algunos datos. Entonces
ejecutamos el siguiente comando Python para determinar si existe alguna otra variable con missing
values.
print(data.isnull().any())
Después de ejecutar el primer comando se nota que la variable Age también posee missing values, ya
que marca True en el ejemplo 888. Vamos a ejecutar un comando Python para calcular un sumario de
todos los missing values en todo el data set.
print(data.isnull().sum())
Finalmente, se determina que existen 177 ejemplos para la variable Age que no poseen valor. Lo mismo
sucede con Cabin and Embarked.
Es muy importante eliminar o tratar los missing values ya que si no lo hacemos podría generarse los
siguientes errores:
● El algoritmo no soporta missing values y falla
● El modelo entrenado considera ejemplos erróneos, por tanto, los resultados no son óptimos
● El modelo podría ser biased para alguna de las clases (Tener preferencia)
De la misma forma, este problema puede ser resuelto de varias formas, y la forma elegida queda a
criterio del data scientist y la información que considere relevante para solucionar el problema. Entre las
posibles opciones tenemos:
● Eliminar completamente la columna con el missing value.
● Calcular el missing value utilizando alguna técnica estadística como media, moda o mediana.
● Calcular el missing value utilizando algoritmos de regresión
● Generar un valor dummy, etc.
Si por ejemplo eligiéramos llenar los faltantes con datos dummy podríamos hacerlo de la siguiente
forma. (Aunque esta técnica no la aplicaremos en nuestro dataSet)
data['Cabin'] = data['Cabin'].fillna('No review')
print(data.head())
DATOS DUPLICADOS
Es muy común encontrarnos con un conjunto de ejemplos duplicados, tanto para los atributos como
para la clase. Es importante eliminar dichos registros ya que podrían hacer que nuestro modelo sea
biased hacia alguna clase y por tanto nuestra precisión disminuya.
Verificamos si hay datos duplicados en nuestro dataSet con el siguiente comando y notamos que en
nuestro caso no existen duplicados.
print(data.duplicated().any())
En caso existieran duplicados los eliminaríamos con el siguiente comando
data.drop_duplicates()
*******************************************************************
3RA PARTE DE EXPO
*******************************************************************
DATOS NO RELEVANTES
Esta fase es muy importante, ya que si consideramos que una variable no va a aportar nada a nuestro
modelo es mejor eliminarla. En nuestro dataSet eliminaremos los valores de PassangerId (id del
pasajero), Name( nombre), Ticket(numero de ticket) y Cabin(numero de cabina). Ya que a simple vista
no aportan información.
Otra opción es que a nuestro ojo humano parezcan inútiles, pero tal vez el clasificador puede encontrar
un patrón interesante. Esto solo se puede determinar con prueba y error. O haciendo algún análisis
estadístico que indique la relevancia dentro de nuestro dataSet.
OUTLIERS (RUIDO)
En general, los dataSets siempre contienen cierto nivel de ruido que es importante identificar y tratar.
Con ruido nos referimos a valores muy diferentes a los considerados en nuestra variable.
Por ejemplo, si notamos que las edades van entre 1 a 70 podríamos concordar que, dado el dataset, son
valores normales. Pero que pasa si dentro de esos valores notamos valores negativos, o
exageradamente altos o pequeños. Eso es definitivamente un outlier.
Al igual que en los otros casos hay muchas maneras de detectarlos y tratarlos. Nosotros seleccionamos
el valor skewness. Esto básicamente hará un cálculo con todos los ejemplos para el atributo y devolverá
un valor. Si el valor esta en el rango -1 a 1 significa que la data es consistente y no presenta outliers.
Cualquier valor fuera de esos rangos es considerado outlier.
En nuestro dataSet hay 2 variables que podrían presentar outliers, así que las verificaremos con el
siguiente comando Python.
En el resultado Podemos observar que Age esta dentro de los parámetros normales. Ya en Fare se
detectan outliers.
La forma de resolver esto es similar a como tratamos los missing values.
*******************************************************************
4TA PARTE DE EXPO
*******************************************************************
HOMOGENEIZAR DATOS
En este dataSet consideramos que la variable Sexo y Embarked puede contribuir a nuestro modelo así
que decidimos utilizarla. Sin embargo, en el dataSet original son campos string. En este caso se opto por
convertirlos a numéricos
Analizando nuestras funciones Python
Se decidió tomar las siguientes acciones:
● Eliminar de nuestro dataSet las columnas PassengerId, Cabin, Ticket y Name.
● Trataremos los missing values de Age con la media de todos los valores. Es decir se va a calcular
de toda la columna la media (np.mean(data[‘Age’]) y ese valor va a ser llenado en todo campo
vacío que encontremos data[‘Age’].fillna.
● En el caso de Embarked hay solo 2 missing values por lo que podríamos eliminar por completo
los 2 ejemplos, pero se decidió utilizar la moda. Es decir, el valor que mas se repite en la
columna. Y llenarlo en todo campo vacío.
● Ya que se determino que existen outliers en la variable Fare, se decidió reemplazarlo con la
mediana. En el comando np.where nos aseguramos de cambiar únicamente los campos cuyo
valor sea mayor a la mediana, el resto queda tal cual fue registrado en el dataSet.
● Finalmente, convertiremos a numéricos las variables de Sex y Embarked. Para esto realizamos
un mapeo del valor actual (por ejemplo, male) y le indicamos a que se va a convertir (0)
Como paso siguiente vamos a realizar una visualización de nuestro dataSet para determinar si las
clases están balanceadas.
Se va a realizar el conteo de supervivientes agrupando nuestro dataSet por la variable que sabemos
representa nuestra clase, en este caso Survived.
En el grafico observamos que las clases están balanceadas. Ya que tenemos un conjunto consistente
de datos de entrenamiento para ambas clases. Si nos hubiéramos encontrado con un dataSet
desbalanceado se hubiera tenido que aplicar otra técnica de limpieza para realizar el balanceo.
*******************************************************************
5TA PARTE DE EXPO
*******************************************************************
En este punto ya tenemos nuestro dataSet listo para ser utilizado. Pero siempre es importante, en
este tipo de entrenamiento supervisado, dividirlo en dataSet de entrenamiento y dataSet de
prueba. Este último nos servirá para poder hacer las validaciones respectivas del modelo.
Para esto estamos utilizando una funcionalidad ya existente de la librería sklearn. Para esto tenemos
que indicar cuales variables del dataSet van a representar los atributos y cuál va a ser la clase.
Adicionalmente, en el comando train_size = .75, se esta indicando que 75% del dataSet será
utilizado para entrenamiento y lo restante para las pruebas. Este número también es a criterio del
data scientist.
2. ENTRENAMIENTO DEL MODELO
Actualmente, existen muchas librerías de Machine Learning (ML) que incluyen los algoritmos e
incluso incluyen formas rápidas de validación.
PERCEPTRON SKLEARN
Dado que esta es una clase preconstruida lo único que se necesita, o se puede realizar, es especificar
algunas configuraciones. Sin embargo, si algunos campos no se consideran en el constructor el
algoritmo toma loso valores que fueron establecidos por defecto.
La instrucción p.fit(Atributos,Clases) es la que invoca a la función, e internamente hace todos los
cálculos. En los 2 prints se van a visualizar los resultados utilizando el dataSet de entrenamiento y el
dataSet de prueba. Este ultimo es el que mas nos interesa ya que es validación.
Como resultado del ultimo print se obtiene los siguientes resultados que analizaremos mas
adelante.
*******************************************************************
6TA PARTE DE EXPO
*******************************************************************
PERCEPTRON
Para este caso se codifico el algoritmo de perceptrón y al igual que en el caso anterior se va a utilizar
el mismo dataSet de entrenamiento y prueba.
Como primer paso se definió una clase y en el constructor se están dejando algunos valores por
defecto, tales como learningRate, numero de iteraciones, etc.
El corazón de nuestro algoritmo esta en la siguiente función
Estamos pasando como parámetro self(el propio objeto de la clase que tendrá acceso a los valores
por defecto), Atributos que corresponde al conjunto X_train y Clase que corresponde a y_train.
Los atributos que vienen en los parámetros de la función son de tipo dataFrame. Si hacemos un
Atributos.shape podremos notar que es una tupla<#Ejemplos(filas),#Atributos(variables)>
Para los pesos solo necesitamos un array[#Atributos] ya que los pesos se irán actualizando con cada
iteración.
Dejamos un array de errores en blanco, ya que aquí vamos a guardar la cantidad de errores que se
cometió en cada iteración.
En la variable data vamos a tener un array[Atributos][Clase].
Pd.DataFrame(Atributos).to_numpy() -> Va a convertir el dataFrame a un array de atributos. De tal
forma que tendremos un valor de la siguiente forma [a1,a2,a3,a4,a5,a6,a7], donde a representa a 1
atributo del dataSet. En el caso de Clase, también será representado como un array [c1].
Zip va a unir tanto el array de Atributos como el de Clases dentro de una misma línea. (Nos servirá
para el for)
Vamos a iniciar el algoritmo con un for hasta que se cumpla el número de iteraciones que
especificamos al inicio.
Vamos a hacer un for para la variable data y vamos a recorrer línea a línea sus valores que
denominaremos valor y valorY.
Empezamos a hacer los cálculos en cada línea y empezamos con la sumatoria de los valores
salida = np.dot(valorX,self.pesos)+self.bias
Recordemos que estamos tratando con array de datos. Np.dot() va a realizar la multiplicación del
array valor * array de pesos (inicializados en 0) y a eso le sumara el bias.
El valor de la variable salida es un valor flotante, por lo que en la siguiente línea tenemos que utilizar
la función de activación
pSalida = 1 if salida>0 else 0
pSalida ahora esta normalizada a 0 o 1 y representa a la salida que nuestro modelo predijo.
if pSalida != valorY:
error += 1
self.pesos += self.learningRate * (valorY-pSalida) * valorX
self.bias = np.sum(self.learningRate * (valorY-pSalida))
Vamos a comparar la salida predecida con el valor que esperábamos saliera (el valor de la clase
especificada en el dataSet). Si estos valores son diferentes indica que hubo un error y los pesos
deben ser recalculados.
Tenemos que recalcular tanto pesos como bias. En el caso de pesos seguimos hablando de un array
así que simplemente se utiliza la formula y Python calcula el valor para cada elemento del array.
Al finalizar todas las iteraciones vamos a tener un array de Errores, que podemos plotear para ir
viendo como va mejorando o empeorando el modelo.
Podemos observar que al inicio se tuvo muchos errores, y con el pasar de las iteraciones estos van
disminuyendo. En 1000 iteraciones notamos que el error bajo un poco. Los resultados se podrían
mejorar aumentando el número de iteraciones, modificando el learninig rate o tal vez removiendo
algunas columnas que tal vez no estén aportando información importante a nuestro modelo.
Al finalizar nuestras iteraciones determinamos que los pesos finales fueron los siguientes:
Con esos pesos calculados ahora tenemos que probar el modelo. Para lo cual escribimos la siguiente
función:
En este caso nuestros parámetros de entrada Atributos, Clase son representados por X_test y y_test.
Para efectos de visualización vamos a llevar un conteo de valores correcto y errores, inicializados en
0 en un inicio
Al igual que hicimos en el entrenamiento, definimos nuestra variable data con los arrays de
Atributos y Clase
En este caso no necesitamos hacer un for hasta que sea el numero de iteraciones. Eso es solo para el
entrenamiento. Pero lo que si necesitamos es ir línea por línea de nuestro array y calcular la salida
con los pesos que ya establecimos.
Calculamos la salida con self.pesos que contiene los últimos valores y self.bias que también
representa el ultimo valor calculado.
Aplicamos la misma función de activación que aplicamos en el entrenamiento y guardamos la salida
en la variable pSalida.
Para poder calcular nuestra matriz de confusión vamos a ir almacenando el valor predecido y el
valor deseado en los arrays y_Actual y y_Predicted.
Si los valores son iguales entonces sumamos correcto +1 , caso contrario error +1
La variable matriz_salida va a juntar los arrays de y_Actual y y_Predicted en una sola variable. Nos
servirá para la matriz de confusión.
Un simple ploteo del conjunto de entrenamiento y obtenemos el siguiente grafico y notamos que
acertó bastantes ejemplos.
*******************************************************************
PUEDE VOLVER A EXPLICAR LOS 2 QUE MENOS EXPLICARON
*******************************************************************
3. EVALUACION DEL MODELO
La parte más importante del análisis es determinar que tanto éxito tuvo nuestro modelo. Si bien, en
el grafico anterior, se observa que se acertaron muchos ejemplos es necesario hacer cálculos
estadísticos.
Lo mas habitual es fijarnos en la matriz de confusión generada y revisar la cantidad de Falsos
Positivos (FP), Falsos Negativos (FN) que fueron generados
Una matriz de confusión esta dividida en 4 cuadrantes, y con los valores allí expresados se pueden
calcular precisión, eficacia, entre otros valores
Dentro de nuestra función de Testeo estamos construyendo la matriz
Vamos a generar un dataFrame con la matriz de salida que calculamos previamente. E indicamos
que tal array tiene 2 columnas.
Utilizamos la función de pandas denominada crosstab para realizar el cruce de datos y obtenemos la
siguiente matriz
Finalmente, utilizando la matriz hacemos el calculo de TP,FP, etc y determinamos la precisión y
accuracy
Accuracy: Indica cuantas veces el modelo predijo correctamente el resultado.
Precision: Determina que tan bueno fue el modelo al momento de predecir los resultados
Recall: Indica cuantas veces el modelo pudo detectar una clase
Referencia: https://www.mage.ai/blog/definitive-guide-to-accuracy-precision-recall-for-product-
developers#:~:text=Accuracy%20tells%20you%20how%20many,to%20detect%20a%20specific
%20category.
Referencia: https://towardsdatascience.com/accuracy-precision-recall-or-f1-331fb37c5cb9