Revisaba el algoritmo percentrón, como se explica en los tutoriales que hay por internet, es un algoritmo que recibe una entrada binaria (1 o 0), que suele ser un vector, donde cada elemento del vector está asociado a un peso. Además cada elemento del vector tiene asociado una etiqueta binaria. Lo que se desea con el algoritmo perceptrón es hallar parámetros (también llamados "pesos") que predigan correctamente la etiqueta si se ingresa un nuevo vector.
El perceptrón sólo actualiza sus pesos si predice mal una etiqueta. No
siempre es necesario un condicional (un if... else...), si una etiqueta
ha sido predicha correctamente, el error será cero y los pesos
mantendrán su valor. Esta idea se usa en How To Implement The Perceptron Algorithm From Scratch In Python - MachineLearningMastery.com
El algoritmo implementado en esta web https://dafriedman97.github.io/mlbook/content/c3/s2/perceptron.html es uno de los más simples que he encontrado, pero hay un error. Teóricamente el algoritmo Perceptrón debería aproximarse bastante a una clasificación correcta, pero casi nunca del 100%. En esta web siempre resulta que el algoritmo no converge.
Hallé dos errores. una es en la función sign. No es necesario que devuelva {-1, +1}. Las etiquetas ya están clasificadas como {0, 1} así que las predicciones del perceptrón pueden dejarse con esos valores. Al cambiar la función sign también tuve que cambiar estas líneas:
En mi caso basta evaluar cada elemento del vector de etiquetas:
El otro error es al evaluar si el algoritmo converge. Pide una exactitud del 100% para la convergencia:
Esto casi nunca se consigue. No eliminé estas líneas porque en casos muy raros sí puede cumplirse que las etiquetas predichas y las reales sean todas iguales.
El código corregido es:
from tkinter import Y
import numpy as np
np.set_printoptions(suppress=True)
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
class Perceptron:
def sign(self, a):
if a > 0:
return 1
else:
return 0
def standard_scaler(self, X):
mean = X.mean(0)
sd = X.std(0)
return (X - mean)/sd
def fit(self, X, y, n_iter = 10**3, lr = 0.001, add_intercept = True, standardize = True):
# Add Info #
if standardize:
X = self.standard_scaler(X)
if add_intercept:
ones = np.ones(len(X)).reshape(-1, 1)
self.X = X
self.N, self.D = self.X.shape
self.y = y
self.n_iter = n_iter
self.lr = lr
self.converged = False
self.accuracy = 0
vsign = np.vectorize(self.sign)
# Fit #
beta = np.random.randn(self.D)/5
for i in range(int(self.n_iter)):
# Form predictions
yhat = np.dot(self.X, beta)
yhat = vsign(yhat)
# Check for convergence
if np.all(yhat == self.y):
self.converged = True
self.iterations_until_convergence = i
break
# Otherwise, adjust
for n in range(self.N):
yhat_n = self.sign(np.dot(beta, self.X[n]))
if (self.y[n] != yhat_n):
beta += self.lr * self.y[n]*self.X[n]
# Return Values #
self.beta = beta
self.yhat = yhat
print(self.y[:50])
print(self.yhat[:50])
accuracy_true = self.y == self.yhat
self.accuracy = np.count_nonzero(accuracy_true)/self.N * 100
print("accuracy: ", self.accuracy, "%")
def main():
# import data
cancer = datasets.load_breast_cancer()
X = cancer['data']
y = cancer['target']
perceptron = Perceptron()
perceptron.fit(X, y, n_iter = 1e2, lr = 0.01)
if __name__ == "__main__":
main()
El resultado es: