
De forma gráfica os voy a presentar algunas técnicas de clasificación supervisada de las más empleadas in Machine Learning y podremos ver cómo se comportan de forma gráfica en el plano. Como siempre, prefiero ilustrarlo a entrar in temas teóricos y, para esta tarea, se me ha ocurrido pintar una letra O y comenzar a trabajar con Python, así de simple. Lo primero es tener los datos; evidentemente serán puntos aleatorios en el plano donde pintamos una variable dependiente con forma de O:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
largo = 10000
df = pd.DataFrame(np.random.uniform(0, 100, size=(largo, 2)), columns=list('XY'))
dependiente1 = np.where(((df.X - 50)**2 / 20**2 + (df.Y - 50)**2 / 40**2 > 1), 1, 0)
dependiente2 = np.where(((df.X - 50)**2 / 30**2 + (df.Y - 50)**2 / 50**2 > 1), 1, 0)
dependiente = dependiente1 - dependiente2
plt.scatter(df.X, df.Y, c=dependiente, marker=".")
plt.show()
Se crea un data.frame con 10.000 registros y dos variables aleatorias con valores entre 0 y 100 (X e Y). Soy consciente de la forma en la que se obtiene la variable dependiente (no entiendo cómo funciona np.where() con condiciones múltiples) y por ello toman valor 1 aquellas observaciones del plano que están entre las dos elipses que pinto dentro del plano. Con todo esto tenemos unos datos como ilustra el scatter plot con el que se inicia esta entrada. El siguiente paso será dividir los datos en validación y test mediante train_test_split():
# Dividimos en validacion y test
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(df, dependiente,
stratify=dependiente,
test_size=0.5,
random_state=123)
Ahora vamos a estudiar gráficamente cómo se comportan algunos algoritmos de Machine Learning para clasificar la letra O en el espacio. Empezamos por los árboles de decisión:
from sklearn.tree import DecisionTreeClassifier
arbol_1 = DecisionTreeClassifier(random_state=0, max_depth=7, min_samples_leaf=50)
arbol_1.fit(X_train, y_train)
predichos = arbol_1.predict(X_test)
plt.scatter(X_test.X, X_test.Y, c=predichos, marker=".", cmap=plt.cm.Blues)
plt.show()

No se selecciona un árbol muy complejo: solo 7 nodos y con un mínimo de 50 observaciones por nodo; con estas consideraciones, el árbol lo que hace es crear 4 bloques en el plano: al algoritmo le cuesta trazar las zonas no lineales. Con unas características parecidas, empleamos clasificación por Random Forest; donde antes había un árbol, ahora tenemos un bosque:
from sklearn.ensemble import RandomForestClassifier
bosque_1 = RandomForestClassifier(random_state=0, max_depth=7, min_samples_leaf=50)
bosque_1.fit(X_train, y_train)
predichos = bosque_1.predict(X_test)
plt.scatter(X_test.X, X_test.Y, c=predichos, marker=".", cmap=plt.cm.Blues)
plt.show()

Con una complejidad parecida ya no hay bloques; ahora tenemos «pequeños cuadrados» que son capaces de trazar las zonas no lineales pero no todas: necesita una mayor complejidad para poder clasificar mejor la letra O. Una técnica de clasificación que nos va a funcionar muy bien son los $k$ vecinos más cercanos (AKA k-NN), donde los puntos en el espacio no van a suponer un problema para esta técnica:
from sklearn.neighbors import KNeighborsClassifier
vecinos_1 = KNeighborsClassifier(n_neighbors=3, algorithm="auto").fit(X_train, y_train)
predichos = vecinos_1.predict(X_test)
plt.scatter(X_test.X, X_test.Y, c=predichos, marker=".", cmap=plt.cm.Blues)
plt.show()

Ahí lo tenemos: lo clava solo con 3 vecinos y eligiendo de forma automática el algoritmo de clasificación; los datos de test quedan perfectamente clasificados, punto a punto el algoritmo lo clava a excepción de algún punto en el borde. Una situación parecida debemos encontrarnos para las máquinas de vectores de soporte, conocidas como SVM, una técnica de clasificación que me gusta:
from sklearn.svm import SVC
svm_1 = SVC(C=1, tol=0.1)
svm_1.fit(X_train, y_train)
predichos = svm_1.predict(X_test)
plt.scatter(X_test.X, X_test.Y, c=predichos, marker=".", cmap=plt.cm.Blues)
plt.show()

Excepcional comportamiento clasificatorio; comentar que Python sorprende gratamente a la hora de emplear este tipo de algoritmos: va más deprisa que R. Por último, tenemos la clasificación con perceptrón multicapa, a la que no le auguro un buen funcionamiento debido a la complejidad que presenta la letra O:
from sklearn.neural_network import MLPClassifier
mlp_1 = MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(30, 30, 30),
random_state=1, learning_rate_init=0.001, max_iter=200)
mlp_1.fit(X_train, y_train)
predichos = mlp_1.predict(X_test)
plt.scatter(X_test.X, X_test.Y, c=predichos, marker=".", cmap=plt.cm.Blues)
plt.show()

Observamos cómo una red neuronal con 3 capas con 30 unidades ocultas (un perceptrón muy complejo) no puede clasificar con precisión la letra O. In este caso es muy interesante hacer el scatter plot con colores donde graduamos la probabilidad que asigna el modelo, no solo graficar la predicción:
proba = mlp_1.predict_proba(X_test)
proba = pd.DataFrame(proba)[1]
plt.scatter(X_test.X, X_test.Y, c=proba, cmap=plt.cm.Blues)
plt.colorbar()
plt.show()

El resultado es interesante, puesto que las probabilidades que arroja la predicción son muy conservadoras a excepción de aquellos lugares en el plano donde tiene una alta certeza de encontrar un 1. Hasta aquí no os he contado nada que no se pueda encontrar navegando un poco por la red; sin embargo, en una sola entrada tenemos un pequeño manual de sklearn donde analizamos:
DecisionTreeClassifierRandomForestClassifierKNeighborsClassifierSVCMLPClassifier
Espero que os pueda ser de utilidad. Saludos.