Problema de clasificación¶

In [1]:
# Importaciones necesarias
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt

# Cargamos los datos
banknotes = pd.read_csv('https://cursopypagina.github.io/CursoPy/banknotes.csv')
In [2]:
# Exporamos la informacion sobre nuestros datos
banknotes.head()
Out[2]:
variace skewness curtosis entropy class
0 3.62160 8.6661 -2.8073 -0.44699 0
1 4.54590 8.1674 -2.4586 -1.46210 0
2 3.86600 -2.6383 1.9242 0.10645 0
3 3.45660 9.5228 -4.0112 -3.59440 0
4 0.32924 -4.4552 4.5718 -0.98880 0
In [3]:
banknotes.shape
Out[3]:
(1372, 5)

banknotes es una base de datos sobre la autentificación de billetes de dólares mediante 4 características, las cuales fueron calculadas realizando operaciones matemáticas sobre imágenes de los billetes de dólares. La clasificación de si el billete es verdadero o no está en la columna class que solo tiene ceros y unos

Indaguemos graficamente sobre nuestros datos

In [4]:
sns.pairplot(banknotes, hue='class')
plt.show()
In [5]:
banknotes['class'].value_counts()
Out[5]:
0    762
1    610
Name: class, dtype: int64

de donde hay características para las que las clases se extienden notablemente, esto nos da una intuición de que nuestras clases son fácilmente separables.

Ahora bien, dado que tenemos 4 características, entonces nuestra capa de entrada tendrá 4 neuronas, no tendremos capas ocultas y la capa de salida tendrá sólo una neurona en la cual implementaremos la función de activación sigmoide, donde para valores $<0.5$ asignaremos la etiqueta 0 y para valores $\geq5$ le asignaremos la etiqueta 1. Dichos valores lo interpretaremos como probabilidades, donde 1 nos dirá que el billete es falso.

Procedemos a crear nuestro modelo

In [6]:
# Realizamos las importaciones necesarias
from keras.models import Sequential
from keras.layers import Dense
import numpy as np

# Fijamos una semilla
np.random.seed(123)

# Instanciamos el modelo
model = Sequential()

# Capa de entrada de 4 neuronas y capa de salida de una neurona
model.add(Dense(1, input_shape=(4,), activation='sigmoid'))

# Copilacion del modelo.
# El optimizador sera: descenso del gradiente estocastico
model.compile(optimizer='sgd', loss='binary_crossentropy', metrics=['accuracy'])

# Vemos un resumen sobre nuestro modelo
model.summary()
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense (Dense)               (None, 1)                 5         
                                                                 
=================================================================
Total params: 5
Trainable params: 5
Non-trainable params: 0
_________________________________________________________________

Convertimos nuestros datos a un NumPy array:

In [7]:
banknotes = np.array(banknotes)

Realizamos la división de los datos

In [8]:
from sklearn.model_selection import train_test_split
# Puntos
X =  banknotes[:, 0:4]
# Etiquetas
y = banknotes[:, 4]

# Division de los datos
X_train, X_test, y_train, y_test = train_test_split(
                                        X,
                                        y,
                                        train_size   = 0.25,
                                        random_state = 123)

después, ajustamos el modelo y vemos la evaluación del mismo

In [9]:
# Ajustamos el modelo
model.fit(X_train, y_train, epochs=20, verbose=0)

# Evaluacion del modelo
scores = model.evaluate(X_train, y_train)
print('%s: %.4f%%' % (model.metrics_names[1], scores[1] * 100))
11/11 [==============================] - 0s 1ms/step - loss: 0.2066 - accuracy: 0.9446
accuracy: 94.4606%

Procedemos a realizar la predicción y comparamos dichas predicciones con los valores reales

In [10]:
# Realizamos las predicciones
predicciones = model.predict(X_test).round()

# Creamos un dataframe vacio
dict1 = {'Predicción': [0 for i in range(X_test.shape[0])], 
         'Valor real': [0 for i in range(X_test.shape[0])]}
df = pd.DataFrame(dict1)

# Llenamos el dataframe
for i in range(X_test.shape[0]):
    df.iloc[i][0] = predicciones[i][0]
    df.iloc[i][1] = y_test[i]
    
# Comparamos
df
33/33 [==============================] - 0s 968us/step
Out[10]:
Predicción Valor real
0 0 0
1 0 0
2 0 0
3 0 0
4 1 1
... ... ...
1024 0 0
1025 1 1
1026 0 0
1027 1 1
1028 0 0

1029 rows × 2 columns

In [11]:
count = 0
for i in range(1029):
    if df.iloc[i][0] != df.iloc[i][1]:
        count += 1
count
Out[11]:
52

nuestro modelo se equivocó 61 veces.


Veamos algunos gráficos:

In [12]:
# Datos de prueba:
plt.figure(figsize=(4,4))
import matplotlib.pyplot as plt

# Graficamos
for i in range(X_test.shape[0]):
    plt.plot(X_test[i][0], X_test[i][1], marker="o", color="#02FFEF")
plt.title('Varianza vs Asimetría')
plt.show()

Veamos el mismo gráfico con la separación hecha por nuestra red neuronal

In [13]:
plt.figure(figsize=(4,4))
# Graficamos
for i in range(X_test.shape[0]):
    # si la etiqueta es 1 (billetes falsos), el color es morado
    if predicciones[i][0] == 1:
        plt.plot(X_test[i][0], X_test[i][1], marker="o", color="#9D02FF")
    # si la etiqueta es 0 (billetes verdaderos), el color es maguenta
    else:
        plt.plot(X_test[i][0], X_test[i][1], marker="o", color="#FF02A3")
plt.title('Varianza vs Asimetría')
plt.show()

Veamos ahora el gráfico original

In [15]:
banknotes = pd.read_csv('https://cursopypagina.github.io/CursoPy/banknotes.csv')
banknotes.columns
Out[15]:
Index(['variace', 'skewness', 'curtosis', 'entropy', 'class'], dtype='object')
In [16]:
plt.figure(figsize=(4,4))
sns.scatterplot(data=banknotes, x="variace", y="skewness", hue='class')
plt.show()