<jupyter_start><jupyter_text>Demonstração de Regressão Logística com Limites Lineares_Fonte original (referência de desenvolvimento e implementação): [Homemade Machine Learning](https://github.com/trekhleb/homemade-machine-learning)_> ☝ Antes de iniciar nesse exemplo pode ser interessante revisar conceitos de:> - ⚙️ [Matemática atrás da regressão](https://github.com/aceiro/homemade-machine-learning/tree/master/homemade/logistic_regression/README_ptBR.md)> - ⚙️ [Código Fonte da regressão logística em Python (_em inglês_)](https://github.com/trekhleb/homemade-machine-learning/blob/master/homemade/logistic_regression/logistic_regression.py)**Regressão Logística** é uma uma maneira apropriada para conduzir uma análise de regressão quando variáveis dependentes forem definidas em categorias (dicotomia) binárias. Como todas as análises de regressão a regressão logística é uma análise preditiva. A regressão logística é utilizada para descrever dados e explicar o relacionamento enrte uma variável binária dependente de uma ou mais variáveis nominais, comuns, intervalares ou em níveis de relacionamento entre variáveis independentes.A Regressão Logística é utilizada quando uma variável dependente (alvo/_target_) é categórica.Por exemplo:- Para previsão se um e-mail é um spam (`1`) ou não (`0`).- Se uma transação eletrônica é fraudulenta (`1`) ou não (`0`).- Se um tumor é malígno (`1`) ou não (`0`).- Se um componente eletrônico, mecânico ou peça tem defeito (`1`) ou não (`0`).> **Projeto de exemplo:** Nesse exemplo, iremos classificar três espécies de flores Iris (`Iris setosa`, `Iris virginica` e `Iris versicolor`) baseada nos parâmetros `petal_length` e `petal_width`.<jupyter_code># Esses dois comandos são utilizados para facilitar o processo de depuração
# Fazendo isso, toda alteração no módulo de logistic_regression estarão disponíveis aqui.
%load_ext autoreload
%autoreload 2

# Adiciona a raiz do projeto para execução
import sys
sys.path.append('../..')<jupyter_output><empty_output><jupyter_text>Importando as dependências- [pandas](https://pandas.pydata.org/) - biblioteca que nós iremos utilizar para carregar e exibir os dados em uma tabela- [numpy](http://www.numpy.org/) - biblioteca que nós iremos utilizar para operações em algebra linear- [matplotlib](https://matplotlib.org/) - biblioteca que nós iremos utilizar para plotar os gráficos- [logistic_regression](https://github.com/trekhleb/homemade-machine-learning/blob/master/homemade/logistic_regression/logistic_regression.py) - implementação customizada da regressão logística<jupyter_code># Importa as bibliotecas de terceiros (3rd party)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Importa a implementação customizada da regressão logística 
from homemade.logistic_regression import LogisticRegression<jupyter_output><empty_output><jupyter_text>Carregar os dadosNeste exemplo iremos utilizar o [Iris data set](http://archive.ics.uci.edu/ml/datasets/Iris).Este data set consiste de várias amostras de cada uma das três espécies de Iris (`Iris setosa`, `Iris virginica` e `Iris versicolor`). Quatro características foram medidas para cada amostra: a altura (_length_) e largura (_width_) da sepala e da petala em centímetros. Baseado nesse modelo de quatro características, [Ronald Fisher](https://en.wikipedia.org/wiki/Iris_flower_data_set) elaborou um modelo linear para distinguir cada uma das espécies uma da outra.<jupyter_code># Carrega os dados
data = pd.read_csv('../../data/iris.csv')

# Exibe a tabela
data.head(10)<jupyter_output><empty_output><jupyter_text>Gráfico com os dadosVamos selecionar dois parâmetros `petal_length` e `petal_width` para cada flor e plotar a dependencia da classe (categoria) Iris nesses dois parâmetros.<jupyter_code># Lista de classes e/ou categorias que vamos usar
iris_types = ['SETOSA', 'VERSICOLOR', 'VIRGINICA']

# Selecionando os parâmetros para exibir no gráfico
x_axis = 'petal_length'
y_axis = 'petal_width'

# Traça a dispersão para cada tipo
for iris_type in iris_types:
    plt.scatter(
        data[x_axis][data['class'] == iris_type],
        data[y_axis][data['class'] == iris_type],
        label=iris_type
    )

# Traça os dados.    
plt.xlabel(x_axis + ' (cm)')
plt.ylabel(y_axis + ' (cm)')
plt.title('Tipos de Iris')
plt.legend()
plt.show()<jupyter_output><empty_output><jupyter_text>Prepara os dados para treinamentoVamos extrair dados de `petal_length` e `petal_width` e formar um conjunto de dados de trainamento.<jupyter_code># Pega o número total de amostras
num_examples = data.shape[0]

# Pega as características
x_train = data[[x_axis, y_axis]].values.reshape((num_examples, 2))

# Pega os rótulos
y_train = data['class'].values.reshape((num_examples, 1))<jupyter_output><empty_output><jupyter_text>Inicializa o Modelo de Treinamento> ⚙️ Aqui é onde podemos ajustar o modelo de treinamento. Veja abaixo as opções:- `polynomial_degree` - este parâmetro vai permitir com que você adicione novos parâmetros ao modelo. Mais características mais a curva do modelo será ajustada. - `max_iterations` - este é o número máximo de iterações que o algoritmo de gradiente irá utilizar para encontrar o valor mínimo da função. Baixos valores podem evitar que o gradiente alcance um valor de mínimo. Altos valores vão fazer o algoritmo rodar por muito tempo para ajustar a sua precisão.- `regularization_param` - parâmetros que irão brigar por _overfitting_. Um valor alto aqui, mais simples é o modelo. - `polynomial_degree` - o grau do polinômio (`x1^2 * x2, x1^2 * x2^2, ...`).- `sinusoid_degree` - o grau da função senóide que serve como parâmetro multiplicador nas características (`sin(x), sin(2*x), ...`). Isso vai permitir criar a curva de predição.<jupyter_code># Configura os parâmetros da regressão
max_iterations = 1000     # Número máximo de iterações no gradiente
regularization_param = 0  # Ajuda a ajustar o fit do modelo
polynomial_degree = 0     # O grau de parâmetros adicionais
sinusoid_degree = 0       # O grau da senóide

# Inicializa a regressão
logistic_regression = LogisticRegression(x_train, y_train, polynomial_degree, sinusoid_degree)

# Executa o treinamento
(thetas, costs) = logistic_regression.train(regularization_param, max_iterations)

# Exibe o modelo que foi treinado
pd.DataFrame(thetas, columns=['Theta 1', 'Theta 2', 'Theta 3'], index=['SETOSA', 'VERSICOLOR', 'VIRGINICA'])<jupyter_output><empty_output><jupyter_text>Análise do GradienteO _plot_ abaixo ilustra como a função custo altera o valor para cada iteração. Você deve perceber uma queda.No caso de a função custo aumentar isso significa que gradiente perdeu a referência do valor mínimo da função custo e com cada passo ele passa além do desejado.A partir desse _plot_ você pode ter uma compreensão de como muitas iterações você precisa para otimizar o valor da função custo.<jupyter_code># Desenha o gradiente
labels = logistic_regression.unique_labels
plt.plot(range(len(costs[0])), costs[0], label=labels[0])
plt.plot(range(len(costs[1])), costs[1], label=labels[1])
plt.plot(range(len(costs[2])), costs[2], label=labels[2])

plt.xlabel('Gradient Steps')
plt.ylabel('Cost')
plt.legend()
plt.show()<jupyter_output><empty_output><jupyter_text>Calcula a Precisão do Modelo de TreinamentoCalcula quantas flores a partir do conjunto de treinamento foram corretamente classificadas.<jupyter_code># Faz a predição
y_train_predictions = logistic_regression.predict(x_train)

# Verifica se a porcentagem é precisa - acurácia
precision = np.sum(y_train_predictions == y_train) / y_train.shape[0] * 100

print('Precision: {:5.4f}%'.format(precision))<jupyter_output>Precision: 96.0000%<jupyter_text>Desenha os LimitesVamos construir nosso limite decisórios. Existem linhas que distinguem uma classe de outra. Isso nos ajuda a ter uma clara visão de como satisfatoriamente nosso treinamento foi. Você deve ver uma clara distinção nos três tipos de flores.<jupyter_code># Recupera o número de treinamento
num_examples = x_train.shape[0]

# Configura quantas iterações queremos 
samples = 150

# Gera as faixas de teste para o eixo-x e eixo-y
x_min = np.min(x_train[:, 0])
x_max = np.max(x_train[:, 0])

y_min = np.min(x_train[:, 1])
y_max = np.max(x_train[:, 1])

X = np.linspace(x_min, x_max, samples)
Y = np.linspace(y_min, y_max, samples)

# O eixo-z vai conter nossas predições. Então, vamos pegar nossas predições para cada par de x e y
Z_setosa = np.zeros((samples, samples))
Z_versicolor = np.zeros((samples, samples))
Z_virginica = np.zeros((samples, samples))

for x_index, x in enumerate(X):
    for y_index, y in enumerate(Y):
        data = np.array([[x, y]])
        prediction = logistic_regression.predict(data)[0][0]
        if prediction == 'SETOSA':
            Z_setosa[x_index][y_index] = 1
        elif prediction == 'VERSICOLOR':
            Z_versicolor[x_index][y_index] = 1
        elif prediction == 'VIRGINICA':
            Z_virginica[x_index][y_index] = 1

# Agora, quando nos temos x,y e z sendo calculados pelo setup e nos podemos exibir os limites
for iris_type in iris_types:
    plt.scatter(
        x_train[(y_train == iris_type).flatten(), 0],
        x_train[(y_train == iris_type).flatten(), 1],
        label=iris_type
    )

plt.contour(X, Y, Z_setosa)
plt.contour(X, Y, Z_versicolor)
plt.contour(X, Y, Z_virginica)
    
plt.xlabel(x_axis + ' (cm)')
plt.ylabel(y_axis + ' (cm)')
plt.title('Iris Types')
plt.legend()
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0962148445760203, 'fraction_numerical': 0.007295411292027913, 'mean_word_length': 5.268389662027833, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 41, 'https://': 7, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '80710', 'license': 'MIT', 'n_tokens_mistral': 3479, 'n_tokens_neox': 3384, 'n_words': 1007, 'path': 'notebooks/logistic_regression/logistic_regression_with_linear_boundary_demo_ptBR.ipynb', 'repo_name': 'aceiro/homemade-machine-learning', 'size': '9458'}