Vahid Mirjalili

Python Machine Learning


Скачать книгу

ofrece implementaciones alternativas mediante la clase SGDClassifier, que también soporta aprendizaje online a través del método partial_fit. El concepto que se esconde detrás de la clase SGDClassifier es similar al algoritmo de gradiente estocástico que implementamos en el Capítulo 2, Entrenar algoritmos simples de aprendizaje automático para clasificación para Adaline. Podríamos inicializar la versión del descenso del gradiente estocástico, una regresión logística y una máquina de vectores de soporte con parámetros predeterminados de la siguiente forma:

      >>> from sklearn.linear_model import SGDClassifier

      >>> ppn = SGDClassifier(loss='perceptron')

      >>> lr = SGDClassifier(loss='log')

      >>> svm = SGDClassifier(loss='hinge')

      Otra razón por la cual las SVM gozan de gran popularidad entre los que trabajan con el aprendizaje automático es que pueden ser fácilmente kernelizadas para resolver problemas de clasificación no lineal. Antes de tratar el concepto principal que se esconde detrás de una SVM kernelizada, vamos primero a crear un conjunto de datos de muestra para ver qué aspecto tendría un problema de clasificación no lineal.

      Con el siguiente código, crearemos un sencillo conjunto de datos que tiene la forma de una puerta XOR mediante la función logical_or de NumPy, donde se asignarán 100 muestras a la etiqueta de clase 1 y otras 100 a la etiqueta de clase -1:

      >>> import matplotlib.pyplot as plt

      >>> import numpy as np

      >>> np.random.seed(1)

      >>> X_xor = np.random.randn(200, 2)

      >>> y_xor = np.logical_xor(X_xor[:, 0] > 0,

      ... X_xor[:, 1] > 0)

      >>> y_xor = np.where(y_xor, 1, -1)

      >>> plt.scatter(X_xor[y_xor == 1, 0],

      ... X_xor[y_xor == 1, 1],

      ... c='b', marker='x',

      ... label='1')

      >>> plt.scatter(X_xor[y_xor == -1, 0],

      ... X_xor[y_xor == -1, 1],

      ... c='r',

      ... marker='s',

      ... label='-1')

      >>> plt.xlim([-3, 3])

      >>> plt.ylim([-3, 3])

      >>> plt.legend(loc='best')

      >>> plt.show()

      Después de ejecutar el código, tendremos un conjunto de datos XOR con ruido aleatorio, como se muestra en la siguiente imagen:

      Evidentemente, no podríamos separar correctamente las muestras de las clases positivas y negativas utilizando un hiperplano lineal como límite de decisión a través de la regresión logística lineal o del modelo de SVM lineal que tratamos en secciones anteriores.

      La idea fundamental que hay detrás de los métodos kernel para tratar datos inseparables lineales como estos es crear combinaciones no lineales de las características originales para proyectarlas hacia un espacio de dimensiones mayores, mediante una función de mapeo , donde pasen a ser separables lineales. Como se muestra en la siguiente imagen, podemos transformar, mediante la siguiente proyección, un conjunto de datos bidimensional en un nuevo espacio de características tridimensional donde las clases sean separables:

      Esto nos permite separar las dos clases que aparecen en el gráfico mediante un hiperplano lineal que se convierte en un límite de decisión no lineal si lo volvemos a proyectar en el espacio de características original:

      Para resolver un problema no lineal utilizando una SVM, debemos transformar los datos de entrenamiento en un espacio de características de mayor dimensionalidad mediante una función de mapeo y entrenar un modelo de SVM lineal para clasificar los datos en este nuevo espacio de características. Después, podemos utilizar la misma función de mapeo para transformar nuevos datos no vistos y clasificarlos mediante el modelo de SVM lineal.

      Sin embargo, un problema con este enfoque de mapeo es que la construcción de nuevas características es computacionalmente muy costosa, especialmente si tratamos con datos de mayor dimensionalidad. Y aquí es donde el denominado truco de kernel entra en juego. No entraremos mucho en detalle sobre cómo resolver la tarea de programación cuadrática para entrenar un SVM, ya que a la práctica todo cuanto necesitamos es sustituir el producto escalar por . Con el fin de ahorrarnos el costoso paso de calcular este producto escalar entre dos puntos explícitamente, definimos la denominada función kernel: .

      Uno de los kernels más ampliamente utilizados es la Función de base radial (RBF), también denominada kernel Gaussiana:

      Habitualmente se simplifica como:

      En este caso, es un parámetro libre que debe ser optimizado.

      Más o menos, el término kernel puede ser interpretado como una función de similitud entre un par de muestras. El signo menos invierte la medida de distancia de una puntuación de similitud y, debido al término exponencial, la puntuación de similitud resultante caerá en un rango entre 1 (para muestras exactamente similares) y 0 (para muestras muy diferentes).

      Ahora que ya hemos definido a grandes rasgos cuanto hay detrás del truco de kernel, podemos entrenar una SVM kernelizada que sea capaz de dibujar un límite de decisión no lineal que separe correctamente los datos XOR. En este caso, simplemente utilizamos la clase SVC de scikit-learn que importamos anteriormente y sustituimos el parámetro kernel='linear' por kernel='rbf':

      >>> svm = SVC(kernel='rbf', random_state=1, gamma=0.10, C=10.0)

      >>> svm.fit(X_xor, y_xor)

      >>> plot_decision_regions(X_xor, y_xor, classifier=svm)

      >>> plt.legend(loc='upper left')

      >>> plt.show()

      Como podemos ver en el diagrama resultante, la SVM kernelizada separa los datos XOR relativamente bien:

      El parámetro , que ajustamos en gamma=0.1, se puede entender como un parámetro de corte para la esfera Gaussiana. Si aumentamos el valor de