Problema
El perceptrón (1958) es el primer algoritmo de aprendizaje para una neurona artificial. Predice con una función escalón y aprende de sus errores.
Empieza con todos los pesos y el sesgo en 0. En cada época, recorre los ejemplos en orden y, para cada ejemplo x con etiqueta y (0 o 1):
- predicción = 1 si x · weights + bias > 0, si no 0
- error = y - predicción (es decir, -1, 0 o 1)
- Si error ≠ 0: weights[i] ← weights[i] + learning_rate × error × x[i] para cada i, y bias ← bias + learning_rate × error
Implementa train_perceptron(samples, labels, learning_rate, epochs).
Entrada
samples: m ejemplos con n variables cada uno.
labels: Las m etiquetas, cada una 0 o 1.
learning_rate, epochs: El tamaño del paso y el número de pasadas por los datos.
Salida
Devuelve los pesos finales seguidos del sesgo (n + 1 números).
Restricciones
1 ≤ m ≤ 100, 1 ≤ n ≤ 10, 1 ≤ epochs ≤ 100
0 < learning_rate ≤ 1
-10 ≤ cada variable ≤ 10
Ejemplos
Entrada:
epochs = 1
labels = [0, 0, 0, 1]
samples = [
[0.0, 0.0],
[0.0, 1.0],
[1.0, 0.0],
[1.0, 1.0]
]
learning_rate = 1.0
Salida esperada:
expected = [1.0, 1.0, 1.0]
Entrada:
long long epochs = 1;
std::vector<long long> labels = {0, 0, 0, 1};
std::vector<std::vector<double>> samples = {
{0.0, 0.0},
{0.0, 1.0},
{1.0, 0.0},
{1.0, 1.0}
};
double learning_rate = 1.0;
Salida esperada:
std::vector<double> expected = {1.0, 1.0, 1.0};
Entrada:
long epochs = 1;
long[] labels = new long[] {0, 0, 0, 1};
double[][] samples = new double[][] {
new double[] {0.0, 0.0},
new double[] {0.0, 1.0},
new double[] {1.0, 0.0},
new double[] {1.0, 1.0}
};
double learning_rate = 1.0;
Salida esperada:
double[] expected = new double[] {1.0, 1.0, 1.0};
Explicación
[0, 0]: z = 0, predice 0, correcto. [0, 1] y [1, 0]: también predicen 0, correcto. [1, 1]: predice 0 pero la etiqueta es 1, así que error = 1: los pesos pasan a [1, 1] y el sesgo a 1. Resultado: [1, 1, 1].
Entrada:
epochs = 10
labels = [0, 0, 0, 1]
samples = [
[0.0, 0.0],
[0.0, 1.0],
[1.0, 0.0],
[1.0, 1.0]
]
learning_rate = 1.0
Salida esperada:
expected = [2.0, 1.0, -2.0]
Entrada:
long long epochs = 10;
std::vector<long long> labels = {0, 0, 0, 1};
std::vector<std::vector<double>> samples = {
{0.0, 0.0},
{0.0, 1.0},
{1.0, 0.0},
{1.0, 1.0}
};
double learning_rate = 1.0;
Salida esperada:
std::vector<double> expected = {2.0, 1.0, -2.0};
Entrada:
long epochs = 10;
long[] labels = new long[] {0, 0, 0, 1};
double[][] samples = new double[][] {
new double[] {0.0, 0.0},
new double[] {0.0, 1.0},
new double[] {1.0, 0.0},
new double[] {1.0, 1.0}
};
double learning_rate = 1.0;
Salida esperada:
double[] expected = new double[] {2.0, 1.0, -2.0};
Explicación
Tras 10 épocas el perceptrón ha aprendido la puerta AND: con los pesos [2, 1] y el sesgo -2, solo [1, 1] da z > 0.
Cómo abordarlo
Inténtalo primero por tu cuenta y luego abre las pistas una a una.
Pista 1
Procesa las muestras en orden en cada epoch, porque las actualizaciones tempranas afectan las predicciones posteriores.
Pista 2
Solo actualiza cuando la clase predicha difiera de la etiqueta, y ajusta weights y bias juntos.
Pista 3
La regla de predicción usa una prueba de signo estricta, así que un score de cero cuenta como clase 0.
Complejidad esperada
tiempo O(epochs × m × n), espacio extra O(n)
Referencias
Este reto está adaptado para CodeUtility. Sigue el enunciado y las restricciones indicadas arriba.