Skip to content

Perceptron

Parte 1: Implementação Perceptron

Estrutura do Código

Criaremos uma classe Perceptron

import numpy as np

class Perceptron:
    """
    Implementação do Perceptron

    Parâmetros
    ----------
    learning_rate : float
        A taxa de aprendizado (entre 0.0 e 1.0)
    n_iters : int
        O número de passagens (épocas)

    Atributos
    ---------
    weights
    bias
    """
    def __init__(self, learning_rate=0.01, n_iters=10):
        self.learning_rate = learning_rate
        self.n_iters = n_iters
        self.weights = None
        self.bias = None

    def _activation_function(self, x):
        """
        Função de Ativação Degrau (Heaviside Step Function).
        Retorna 1 se x >= 0, senão retorna 0.
        """
        return np.where(x >= 0, 1, 0)

    def fit(self, X, y):
        """
        Ajusta o modelo aos dados de treinamento.

        Parâmetros
        ----------
        X : array-like, shape = [n_samples, n_features]
            Vetor de treinamento, onde n_samples é o número de amostras
            e n_features é o número de características.
        y : array-like, shape = [n_samples]
            Vetor com os rótulos (labels) alvo.
        """
        n_samples, n_features = X.shape

        # Inicialização dos pesos e bias
        self.weights = np.zeros(n_features)
        self.bias = 0

        y_ = np.array(y)

        for _ in range(self.n_iters):
            for idx, x_i in enumerate(X):
                linear_output = np.dot(x_i, self.weights) + self.bias
                y_predicted = self._activation_function(linear_output)
                # Cálculo do Erro e Atualização dos Pesos
                # A atualização só acontece se houver erro
                error = y_[idx] - y_predicted
                update = self.learning_rate * error

                self.weights += update * x_i
                self.bias += update

    def predict(self, X):
        linear_output = np.dot(X, self.weights) + self.bias
        y_predicted = self._activation_function(linear_output)
        return y_predicted

Parte 2: Exercícios

Exercício 1: Dados Linearmente Separáveis

1. Geração dos Dados

Utilizamos o script data_generation.py para criar duas classes de pontos que estão distantes uma da outra, garantindo a separabilidade linear. Os parâmetros chave são:

# data_generation.py
mean0 = [1.5, 1.5]
cov0 = [[0.5, 0], [0, 0.5]]
mean1 = [5, 5]
cov1 = [[0.5, 0], [0, 0.5]]

Ao executar o script, obtemos a seguinte visualização:

2025-09-21T23:41:49.992343 image/svg+xml Matplotlib v3.10.6, https://matplotlib.org/

Como podemos ver no gráfico, os dois grupos (vermelho e azul) não se misturam, representando um caso ideal para o Perceptron.

2. Treinamento

No script test_perceptron.py, instanciamos nosso Perceptron e o treinamos com 80% dos dados gerados, utilizando o método fit.

# Trecho de test_perceptron.py
# ...
p = Perceptron(learning_rate=0.01, n_iters=10)
p.fit(X_train, y_train)

3. Avaliação (Evaluation)

Após o treinamento, usamos os 20% de dados restantes (o conjunto de teste) para verificar o quão bem o modelo generaliza para dados não vistos.

# Trecho de test_perceptron.py
predictions = p.predict(X_test)
print(f"Acurácia do Perceptron no conjunto de teste: {accuracy(y_test, predictions):.2f}")

Resultado Obtido: Ao executar o script, a acurácia impressa no terminal é 1.00 (ou 100%).

4. Análise

O resultado de 100% de acurácia confirma o Teorema da Convergência do Perceptron, que afirma que o algoritmo sempre encontrará uma solução (uma linha de separação) em um número finito de passos, desde que os dados sejam linearmente separáveis.

Podemos visualizar essa solução plotando a fronteira de decisão que o Perceptron aprendeu:

Acurácia do Perceptron no conjunto de teste: 1.00

2025-09-21T23:41:51.774784 image/svg+xml Matplotlib v3.10.6, https://matplotlib.org/

A linha preta representa a fronteira final encontrada pelo algoritmo. Qualquer ponto de um lado da linha é classificado como uma classe, e qualquer ponto do outro lado é classificado como a outra, separando perfeitamente os dados, que são claramente linearmente separáveis.

Exercício 2: Dados com Sobreposição (Não Linearmente Separáveis)

1. Geração dos Dados

Utilizamos o script data_generation2.py para criar duas classes de pontos com médias mais próximas e maior variância, o que causa uma sobreposição entre elas. Os parâmetros chave são:

# data_generation2.py
mean0 = [3, 3]
cov0 = [[1.5, 0], [0, 1.5]]
mean1 = [4, 4]
cov1 = [[1.5, 0], [0, 1.5]]

Ao executar o script, obtemos a seguinte visualização, onde a mistura entre os pontos vermelhos e azuis é clara:

2025-09-21T23:41:53.678553 image/svg+xml Matplotlib v3.10.6, https://matplotlib.org/

2. Treinamento

O treinamento, realizado pelo script test_perceptron2.py, segue o mesmo procedimento. O Perceptron tentará encontrar a melhor linha reta possível para separar as duas classes.

# Trecho de test_perceptron2.py
p = Perceptron(learning_rate=0.01, n_iters=10)
p.fit(X_train, y_train)

3. Avaliação (Evaluation)

A avaliação é feita da mesma forma, usando o conjunto de teste. No entanto, o resultado esperado é diferente.

# test_perceptron2.py
predictions = p.predict(X_test)
print(f"Acurácia do Perceptron no conjunto de teste com sobreposição: {accuracy(y_test, predictions):.2f}")

Resultado Obtido: Ao executar o script, a acurácia impressa fica em torno de 0.66 (ou 66%). Este valor pode variar ligeiramente devido à aleatoriedade na divisão treino-teste, mas nunca chegará a 100%.

4. Análise

A acurácia abaixo de 100% demonstra a principal limitação do Perceptron: ele só pode encontrar soluções perfeitas para problemas linearmente separáveis. Como os dados se sobrepõem, não existe uma única linha reta que consiga dividir as duas classes sem cometer erros.

O algoritmo não "converge" para uma solução sem erros. Em vez disso, a fronteira de decisão pode oscilar um pouco durante o treinamento. O resultado final, após o número definido de iterações, é a melhor tentativa do Perceptron de minimizar os erros com uma única linha.

A fronteira de decisão, visualizada ao executar o teste, mostra essa tentativa:

Acurácia do Perceptron no conjunto de teste com sobreposição: 0.66

2025-09-21T23:41:57.160220 image/svg+xml Matplotlib v3.10.6, https://matplotlib.org/

A linha preta corta através da área de sobreposição, classificando incorretamente alguns pontos de ambas as classes que estão do lado "errado" da fronteira. Este é o comportamento esperado e ilustra por que modelos mais complexos, como Redes Neurais de Múltiplas Camadas (MLPs), são necessários para resolver problemas não-lineares.