Continuación de https://programacionamartillazos.blogspot.com/2024/07/correccion-del-algoritmo-perceptron-de.html
Ahora toca probar los algoritmos. Para esto hice una pequeña modificación en el código de la web Machine Learning from Scratch y al que yo modifiqué:
Código de Machine Learning from Scratch:
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):
return (-1)**(a < 0)
def to_binary(self, y):
return y > 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
# Fit #
beta = np.random.randn(self.D)/5
for i in range(int(self.n_iter)):
# Form predictions
yhat = self.to_binary(self.sign(np.dot(self.X, beta)))
# Check for convergence
if np.all(yhat == self.sign(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 == -1):
beta += self.lr * self.y[n]*self.X[n]
# Return Values #
self.beta = beta
self.yhat = self.to_binary(self.sign(np.dot(self.X, self.beta)))
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 predict(self, X, y, N):
accuracy_true = 0
for n in range(N):
yhat_n = self.to_binary(self.sign(np.dot(self.beta, X[n])))
if (y[n] == yhat_n):
accuracy_true += 1
accuracy_true = accuracy_true/N * 100
print("accuracy: ", accuracy_true, "%")
def main():
# import data
cancer = datasets.load_breast_cancer()
X = cancer['data']
y = cancer['target']
perceptron = Perceptron()
perceptron.fit(X[:-10], y[:-10], n_iter = 2e2, lr = 0.01)
yy= np.atleast_1d(y[-10:])
perceptron.predict(X[-10:], yy, yy.size)
if __name__ == "__main__":
main()
Código que modifiqué:
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 predict(self, X, y, N):
accuracy_true = 0
for n in range(N):
yhat_n = self.sign(np.dot(self.beta, X[n]))
if (y[n] == yhat_n):
accuracy_true += 1
accuracy_true = accuracy_true/N * 100
print("accuracy: ", accuracy_true, "%")
def main():
# import data
cancer = datasets.load_breast_cancer()
X = cancer['data']
y = cancer['target']
perceptron = Perceptron()
perceptron.fit(X[:-10], y[:-10], n_iter = 2e2, lr = 0.01)
yy= np.atleast_1d(y[-10:])
perceptron.predict(X[-10:], yy, yy.size)
if __name__ == "__main__":
main()
El cálculo de la exactitud se hace en dos momentos, con la data de entrenamiento (dentro de la función fit), y con la data de validación (también de prueba en este caso) dentro de la función predict.
Dentro de la función main, lo que se hace es partir la data en dos pedazos: la data de entrenamiento que no incluye los 10 últimos elementos que se pasan a la función fit, y luego los diez últimos elementos que serán la data de evaluación o prueba, que se pasarán como parámetro a la función predict.
En el algoritmo perceptrón el único parámetro que se debe optimizar es beta (es un vector de valores en realidad), el cual luego se usará en la predicción. Los resultados son:
Código de Machine Learning from Scratch:
Código que modifiqué:
El primer valor "accuracy" es el calculado para la data de entrenamiento, el segundo valor es el resultado con la data de testeo.
Ahora otra prueba pero con menos data de entrenamiento, para esto se cambia en la función main donde dice 10 por cualquier otro valor (debe ser el mismo). Para este ejemplo, voy a coger 100 elementos para que sean los de testeo:
El resultado es:
Código de Machine Learning from Scratch:
Código Modificado:
Ambos códigos son equivalentes, la diferencia entre ambos es menor al 1%, siendo el código original el que calcula el parámetro beta un poquito mejor.
Por otro lado, esto demuestra que el resultado depende de la cantidad de data que tengamos para entrenar el algoritmo. En este ejemplo es muy poca data. Una forma de compensarlo es aumentando el número de iteraciones; pero poner demasiadas, con apenas unos pocos cientos de elementos, se corre el riesgo de "overfitting": es decir sobreentrenar nuestro algoritmo de forma que sólo tenga la precisión necesaria con la data de entrenamiento.