forma gratuita los contenidos adicionales del libro.
Ahora, antes de saltar a la implementación en la sección siguiente, vamos a resumir cuanto acabamos de aprender en un simple diagrama que ilustra el concepto general del perceptrón:
Este diagrama muestra cómo el perceptrón recibe las entradas de una muestra x y las combina con los pesos w para calcular la entrada de red. A continuación, la entrada de red pasa por la función de umbral, que genera una salida binaria -1 o +1; la etiqueta de clase predicha de la muestra. Durante la fase de aprendizaje, esta salida se utiliza para calcular el error de la predicción y actualizar los pesos.
Implementar un algoritmo de aprendizaje de perceptrón en Python
En la sección anterior, hemos aprendido cómo funciona la regla del perceptrón de Rosenblatt. Sigamos adelante. Vamos a implementarla en Python y a aplicarla al conjunto de datos Iris que presentamos en el Capítulo 1, Dar a los ordenadores el poder de aprender de los datos.
Una API perceptrón orientada a objetos
Vamos a tomar un enfoque orientado a objetos para definir la interfaz del perceptrón como una clase de Python, lo cual nos permite iniciar nuevos objetos Perceptron que pueden aprender de los datos mediante un método fit y hacer predicciones mediante un método predict separado. Como norma, agregamos un guion bajo (_) a aquellos atributos que no han sido creados durante la inicialización del objeto sino mediante la llamada de otros métodos del objeto, por ejemplo, self.w_.
Si aún no estás familiarizado con las librerías científicas de Python o necesitas un repaso, puedes consultar estos recursos (en inglés):•NumPy: https://sebastianraschka.com/pdf/books/dlb/appendix_f_numpy-intro.pdf•pandas: https://pandas.pydata.org/pandas-docs/stable/10min.html•Matplotlib: http://matplotlib.org/users/beginner.html |
Esta es la implementación de un perceptrón:
import numpy as np
class Perceptron(object):
"""Perceptron classifier.
Parameters
------------
eta : float
Learning rate (between 0.0 and 1.0)
n_iter : int
Passes over the training dataset.
random_state : int
Random number generator seed for random weight
initialization.
Attributes
-----------
w_ : 1d-array
Weights after fitting.
errors_ : list
Number of misclassifications (updates) in each epoch.
"""
def __init__(self, eta=0.01, n_iter=50, random_state=1):
self.eta = eta
self.n_iter = n_iter
self.random_state = random_state
def fit(self, X, y):
"""Fit training data.
Parameters
----------
X : {array-like}, shape = [n_samples, n_features]
Training vectors, where n_samples is the number of
samples and
n_features is the number of features.
y : array-like, shape = [n_samples]
Target values.
Returns
-------
self : object
"""
rgen = np.random.RandomState(self.random_state)
self.w_ = rgen.normal(loc=0.0, scale=0.01,
size=1 + X.shape[1])
self.errors_ = []
for _ in range(self.n_iter):
errors = 0
for xi, target in zip(X, y):
update = self.eta * (target - self.predict(xi))
self.w_[1:] += update * xi
self.w_[0] += update
errors += int(update != 0.0)
self.errors_.append(errors)
return self
def net_input(self, X):
"""Calculate net input"""
return np.dot(X, self.w_[1:]) + self.w_[0]
def predict(self, X):
"""Return class label after unit step"""
return np.where(self.net_input(X) >= 0.0, 1, -1)
Con esta implementación del perceptrón, ya podemos inicializar nuevos objetos Perceptron con un rango de aprendizaje proporcionado eta y n_iter, que es el número de épocas (pasos por el conjunto de entrenamiento). Mediante el método fit, inicializamos los pesos en self.w_ para un vector
Observa también que este vector contiene pequeños números aleatorios extraídos de una distribución normal con desviación estándar 0.01 con rgen.normal(loc=0.0, scale=0.01, size=1 + X.shape[1]), donde rgen es un generador de números aleatorios NumPy que hemos sembrado con una semilla aleatoria especificada por el usuario, por lo que podemos reproducir, si lo deseamos, resultados previos.
La razón por la cual no ponemos los pesos a cero es que el rango de aprendizaje
>>> v1 = np.array([1, 2, 3])
>>> v2 = 0.5 * v1
>>> np.arccos(v1.dot(v2) / (np.linalg.norm(v1) *
... np.linalg.norm(v2)))
0.0