Consideremos los siguientes datos:
# Importamos una libreria para geenrar datos aleatorios
import random as rd
# Generamos numeros aleatorios distribuidos uniformemente del -1.5 al 1.5
nums = [(rd.uniform(-1.5,1.5), rd.uniform(-1.5, 1.5)) for i in range(2000)]
# Seleccionamos aquello que caen dentro del circulo de radio 0.5
circ = [num for num in nums if (num[0]**2 + num[1]**2) < 0.5]
# Seleccionamos otro conjunto de puntos
no_circ = [num for num in nums
if ((num[0]**2 + num[1]**2) >= 0.8) and ((num[0]**2 + num[1]**2) < 1.6)]
Procedemos a graficar nuestro datos
import matplotlib.pyplot as plt
# Graficamos
for i in range(len(circ)):
plt.plot(circ[i][0], circ[i][1], marker="o", color="#0208FF")
for i in range(len(no_circ)):
plt.plot(no_circ[i][0], no_circ[i][1], marker="o", color="#FF0202")
plt.show()
print(len(circ))
print(len(no_circ))
print(len(circ) + len(no_circ))
336 546 882
Convertiremos a arrays las listas circ y no_circ y los uniremos en un solo array
import numpy as np
circ = np.array(circ)
no_circ = np.array(no_circ)
circ_no_circ = np.concatenate((circ, no_circ), axis=0)
Creamos otro array con el mismo número de filas que el array circ_no_circ pero con una columna y lleno de puros ceros
target = np.zeros((circ_no_circ.shape[0],1))
target.shape
(882, 1)
Ahora, si el punto está dentro del círculo pequeño (el de color azul) le daremos la etiqueta 1, si está fuera de dicho círculo le daremos la etiqueta 0:
for i in range(target.shape[0]):
if ((circ_no_circ[i][0]**2) + (circ_no_circ[i][1]**2)) < 0.5:
target[i][0] = 1
else:
target[i][0] = 0
Veamos algunas comprobaciones
print(circ_no_circ[0])
print(target[0])
print()
print(circ_no_circ[6])
print(target[6])
print()
print(circ_no_circ[520])
print(target[520])
[-0.10088805 -0.64931994] [1.] [-0.02612075 -0.56487313] [1.] [ 0.09082121 -1.22887421] [0.]
# sumamos los unos
target.sum()
336.0
que, en efecto, nos dan el número de puntos totales dentro del círculo de radio 0.5
Vemos entonces que tenemos un problema de clasificación binaria, pues así fue como diseñamos los datos. Pero clasificaremos de nuevo los puntos usando ahora redes neuronales, para ello consideraremos:
Por lo que nuestra red neuronal tendrá dos nodos de entrada (una para cada coordenada de los puntos), una capa oculta con cuatro nodos (el número de nodos propuesto fue obtenido mediante experimentación) y la capa de salida con un nodo (pues recordemos que la salida nos indicará si un valor pertenece a un grupo o no) que tendrá asociada la función de activación sigmoide. La función sigmoide nos arrojará 0 para números obtenido menores al umbral (por defecto el umbral vale 0.5), y 1 para números mayores o iguales al umbral.
Procedemos a crear nuestro modelo en keras:
# Realizamos las importaciones necesarias
from keras.models import Sequential
from keras.layers import Dense
# Fijamos una semilla
np.random.seed(123)
# Instanciamos el modelo
model = Sequential()
# Capa de cuatro neuronas y definimos una forma de entrada
# que consta de 2 neuronas.
# La funcion de activacion sera la tangente hiperbolica
model.add(Dense(4, activation='tanh', input_shape=(2,) ))
# Capa de salida con la funcion de activacion sigmoide
model.add(Dense(1, activation='sigmoid'))
# Copilacion del modelo.
# El optimizador sera: descenso del gradiente estocastico
model.compile(optimizer='sgd', loss='binary_crossentropy', metrics=['accuracy'])
model.summary()
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense (Dense) (None, 4) 12 dense_1 (Dense) (None, 1) 5 ================================================================= Total params: 17 Trainable params: 17 Non-trainable params: 0 _________________________________________________________________
Separamos nuestros datos: datos de entrenamiento y datos de prueba
from sklearn.model_selection import train_test_split
# Puntos
X = circ_no_circ
# Etiquetas
y = target
# Division de los datos
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
train_size = 0.75,
random_state = 123)
print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)
(661, 2) (221, 2) (661, 1) (221, 1)
Procedemos a realizar el ajuste del modelo configurando 1000 épocas
# Ajustamos el modelo
history = model.fit(X_train, y_train, epochs=1000,
verbose=0,
validation_data=(X_test, y_test))
Vemos la evaluación de nuestro modelo sobre los datos de prueba
scores = model.evaluate(X_test, y_test)
print('%s: %.4f%%' % (model.metrics_names[1], scores[1] * 100))
7/7 [==============================] - 0s 1ms/step - loss: 0.1563 - accuracy: 0.9593 accuracy: 95.9276%
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Precisión del modelo')
plt.xlabel('Epoch')
plt.ylabel('Precisión')
plt.legend(['Train', 'Test'])
plt.show()
y notamos que hemos obtenido un buen modelo.
Realizaremos predicciones sobre nuestros datos de prueba:
predicciones = model.predict(X_test).round()
7/7 [==============================] - 0s 3ms/step
Compararemos el valor obtenido de la predicción versus el valor real:
import pandas as pd
# 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)
df
Predicción | Valor real | |
---|---|---|
0 | 0 | 0 |
1 | 0 | 0 |
2 | 0 | 0 |
3 | 0 | 0 |
4 | 0 | 0 |
... | ... | ... |
216 | 0 | 0 |
217 | 0 | 0 |
218 | 0 | 0 |
219 | 0 | 0 |
220 | 0 | 0 |
221 rows × 2 columns
# 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
Predicción | Valor real | |
---|---|---|
0 | 0 | 0 |
1 | 0 | 0 |
2 | 0 | 0 |
3 | 0 | 0 |
4 | 0 | 0 |
... | ... | ... |
216 | 0 | 0 |
217 | 1 | 1 |
218 | 0 | 0 |
219 | 1 | 1 |
220 | 0 | 0 |
221 rows × 2 columns
Nuestra red neuronal sólo se equivoco 12 veces. Veamos cómo se ven los puntos clasificados de acuerdo a a la predicción que realizamos sobre los datos de prueba:
# Graficamos
for i in range(X_test.shape[0]):
# si la etiqueta es 1, el color es azul
if predicciones[i][0] == 1:
plt.plot(X_test[i][0], X_test[i][1], marker="o", color="#0208FF")
# Los puntos dentro del circulo pequenio mal clasificados:
elif predicciones[i][0] == 0 and (X_test[i][0]**2 + X_test[i][1]**2 < 0.5):
plt.plot(X_test[i][0], X_test[i][1], marker="o", color="#FFE902")
# si la etiqueta es 0, el color es rojo
else:
plt.plot(X_test[i][0], X_test[i][1], marker="o", color="#FF0202")
plt.show()