<jupyter_start><jupyter_text>------ Predição sonar (rocha ou mina)Este notebook implementa uma rede neural para predizer se um objeto é uma mina ou uma rocha com base em sinais de um sonar opbtidos em diferentes ângulos.Trata-se de um problema de classificação binária (R-rocha ou M-mina).------  Conjunto de dados- Fonte: https://archive.ics.uci.edu/ml/datasets/Connectionist+Bench+(Sonar,+Mines+vs.+Rocks)O conjunto de dados contém sinais obtidos de uma variedade de ângulos  diferentes. Cada padrão é um conjunto de 60 números no intervalo de 0,0 a 1,0. Cada número representa a energia dentro de uma determinada banda de frequência, integrada ao longo de um determinado período de tempo.Detalhes sobre o conjunto de dados:1. Número de instâncias: 2082. Número de atributos: 60 4. Variável target (classe): o rótulo associado a cada registro contém a letra “R” se o objeto for uma rocha e “M” se for uma mina (cilindro de metal)   Leitura e preparação dos dadosVamos começar importando o arquivo CSV bruto usando o Pandas.<jupyter_code>import pandas as pd

# lê arquivo de dados, atribue NaN para dados faltantes e informa cabeçalho como inexistentes (sem nomes para os atributos)
sonar = pd.read_csv('sonar.all-data.csv', na_values=['?'], header = None)
# imprime as 5 primeiras linha dos dados montados
sonar.head()<jupyter_output><empty_output><jupyter_text>Análise prévia dos dadosImprime o número de dados non-null (não ausentes) e o tipo de cada atributo.<jupyter_code># Mostra o número de dados non-null (não ausentes) e o tipo de cada atributo
print('Informações sobre os dados:\n')
sonar.info()
# Soma o número de dados null (ausentes)
print('\n\nSoma de dados null (vazios):\n')
sonar.isnull().sum()<jupyter_output>Informações sobre os dados:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 208 entries, 0 to 207
Data columns (total 61 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   0       208 non-null    float64
 1   1       208 non-null    float64
 2   2       208 non-null    float64
 3   3       208 non-null    float64
 4   4       208 non-null    float64
 5   5       208 non-null    float64
 6   6       208 non-null    float64
 7   7       208 non-null    float64
 8   8       208 non-null    float64
 9   9       208 non-null    float64
 10  10      208 non-null    float64
 11  11      208 non-null    float64
 12  12      208 non-null    float64
 13  13      208 non-null    float64
 14  14      208 non-null    float64
 15  15      208 non-null    float64
 16  16      208 non-null    float64
 17  17      208 non-null    float64
 18  18      208 non-null    float64
 19  19      208 non-null    float64
 20  20      208 non-null    float64
 21  21      20[...]<jupyter_text>Transforma dados categóricos em números - M => 0 (mina)- R => 1 (rocha)<jupyter_code>sonar.replace(('R', 'M'), (1, 0), inplace=True)
sonar.head()<jupyter_output><empty_output><jupyter_text>Análise (estatística) descritiva dos dadosAnálise descritiva dos dados (resumo).<jupyter_code>sonar.describe()<jupyter_output><empty_output><jupyter_text>Separa os atributos das classesExtrai os atributos e as classes (rótulos) colocando-os em duas variáveis separadas (na forma que o Keras espera).Observe que o Dataframe "sonar" possui 61 colunas.<jupyter_code>sonar = sonar.values
print(type(sonar))
X = sonar[:,0:60].astype(float) # X recebe todas as colunas exceto a última
y = sonar[:,60] # y recebe a última coluna
print(X.shape)
print(y.shape)
print("\nX = \n",X)
print("\ny = \n", y)<jupyter_output><class 'numpy.ndarray'>
(208, 60)
(208,)

X = 
 [[0.02   0.0371 0.0428 ... 0.0084 0.009  0.0032]
 [0.0453 0.0523 0.0843 ... 0.0049 0.0052 0.0044]
 [0.0262 0.0582 0.1099 ... 0.0164 0.0095 0.0078]
 ...
 [0.0522 0.0437 0.018  ... 0.0138 0.0077 0.0031]
 [0.0303 0.0353 0.049  ... 0.0079 0.0036 0.0048]
 [0.026  0.0363 0.0136 ... 0.0036 0.0061 0.0115]]

y = 
 [1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]<jupyter_text>Divide o conjunto de dados em treino e teste<jupyter_code>from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.25,random_state=42)
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)<jupyter_output>(156, 60)
(156,)
(52, 60)
(52,)<jupyter_text>Normaliza os dadosStandardScaler<jupyter_code>from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)<jupyter_output><empty_output><jupyter_text>Criar o modelo de rede neural<jupyter_code>from keras.models import Sequential
from keras.layers import Dense
from tensorflow.python.keras.utils import generic_utils

model = Sequential()
# 1a. camada oculta com 20 neurônios (definição das entradas)
model.add(Dense(20, input_dim=X.shape[1], kernel_initializer = 'he_uniform', activation='relu'))
# 2a. camada oculta com 10 neurônios
model.add(Dense(10, kernel_initializer = 'he_uniform', activation='relu'))
# camada de saída com um neurônio
model.add(Dense(1, activation='sigmoid'))
# sumário (resumo) do modelo
model.summary()<jupyter_output><empty_output><jupyter_text>Compilar o modelo<jupyter_code>model.compile(loss='mse', optimizer='adam', metrics=['accuracy', 'mean_squared_error'])<jupyter_output><empty_output><jupyter_text>Treinar o modelo<jupyter_code>from keras.callbacks import EarlyStopping

early_stop = EarlyStopping(monitor='val_loss', min_delta = 1e-10, patience=5, restore_best_weights = 'True', verbose=1)
history = model.fit(X_train,y_train, validation_data=(X_test,y_test), batch_size=8, epochs=10, callbacks=[early_stop])<jupyter_output>Epoch 1/10
20/20 [==============================] - 14s 28ms/step - loss: 0.3345 - accuracy: 0.5637 - mean_squared_error: 0.3345 - val_loss: 0.3197 - val_accuracy: 0.5769 - val_mean_squared_error: 0.3197
Epoch 2/10
20/20 [==============================] - 0s 3ms/step - loss: 0.3402 - accuracy: 0.5165 - mean_squared_error: 0.3402 - val_loss: 0.2685 - val_accuracy: 0.5769 - val_mean_squared_error: 0.2685
Epoch 3/10
20/20 [==============================] - 0s 2ms/step - loss: 0.2839 - accuracy: 0.5207 - mean_squared_error: 0.2839 - val_loss: 0.2301 - val_accuracy: 0.5769 - val_mean_squared_error: 0.2301
Epoch 4/10
20/20 [==============================] - 0s 2ms/step - loss: 0.2148 - accuracy: 0.6054 - mean_squared_error: 0.2148 - val_loss: 0.2076 - val_accuracy: 0.5962 - val_mean_squared_error: 0.2076
Epoch 5/10
20/20 [==============================] - 0s 3ms/step - loss: 0.2051 - accuracy: 0.6636 - mean_squared_error: 0.2051 - val_loss: 0.1935 - val_accuracy: 0.6154 - val_mean_squared_er[...]<jupyter_text>Avaliação do modeloAlternativamente você pode utilizar de maneira isolada a função **evaluate** para avaliar seu modelo no conjunto de dados desejado.A função **evaluate()** retornará uma lista com dois valores. O primeiro será a perda do modelo no conjunto de dados e o segundo será a precisão do modelo no conjunto de dados.Seus resultados podem variar devido à natureza estocástica do algoritmo. As redes neurais são um algoritmo estocástico, o que significa que o mesmo algoritmo nos mesmos dados pode gerar resultados diferentes.<jupyter_code>model.evaluate(X_test, y_test)<jupyter_output>2/2 [==============================] - 0s 3ms/step - loss: 0.1646 - accuracy: 0.8462 - mean_squared_error: 0.1646<jupyter_text>Análise da função loss (erro/perda)Podemos observar o comportamento da função loss para os dados de treino e de validação plotando um gráfico do histórico do comportamento do valor desta função durante o treinamento.<jupyter_code>import matplotlib.pyplot as plt
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'], '')
plt.xlabel("Épocas")
plt.ylabel('Loss')
plt.title('Função de erro/loss')
plt.legend(['loss', 'val_loss'])
plt.show()<jupyter_output><empty_output><jupyter_text>Análise da métrica de desempenho (acurácia)Podemos também observar o comportamento da precisão do modelo para os dados de treino e de validação plotando um gráfico do histórico do comportamento desta medida durante o treinamento.<jupyter_code>plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'], '')
plt.xlabel("Épocas")
plt.ylabel('Acurácia')
plt.title('Acurácia durante o treinamento')
plt.legend(['accuracy', 'val_accuracy'])
plt.show()<jupyter_output><empty_output><jupyter_text>Fazendo prediçõesÉ possível fazer predições (classificações) utilizando o modelo neural treinado sobre as amostras do conjunto de dados de treinamento fingindo que é um novo conjunto de dados que não vimos antes, sobre o conjunto teste ou qualquer outro conjunto novo.Para isso, basta chamar a função **predict()**. Como estamos usando ua função de ativação sigmóide na camada de saída, então as previsões serão uma probabilidade na faixa entre 0 e 1. Podemos facilmente convertê-las em uma previsão binária nítida para esta tarefa de classificação arredondando-as.<jupyter_code>import numpy as np
from random import randint
y_pred = model.predict(X_test)
y_pred = (y_pred > 0.5)
# imprime as predições para as 10 primeiras amostras do conjunto de dados
for i in range(10):
	print('instância no. %d => %d (expected %d)' % (i, y_pred[i], y_test[i]))<jupyter_output>instância no. 0 => 0 (expected 0)
instância no. 1 => 1 (expected 1)
instância no. 2 => 1 (expected 1)
instância no. 3 => 0 (expected 1)
instância no. 4 => 0 (expected 0)
instância no. 5 => 0 (expected 1)
instância no. 6 => 0 (expected 0)
instância no. 7 => 0 (expected 0)
instância no. 8 => 1 (expected 1)
instância no. 9 => 0 (expected 0)<jupyter_text>Calcula a matriz de confusãoPara se ter uma noção melhor dos resultados das predições realizadas pelo modelo neural treinado pode-se calcular a [**matriz de confusão**](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.confusion_matrix.html) sobre os resultados das classificações.<jupyter_code>from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred)
print(cm)<jupyter_output>[[29  1]
 [ 7 15]]
{'fraction_non_alphanumeric': 0.13412914747626656, 'fraction_numerical': 0.08403045399003665, 'mean_word_length': 3.739420935412027, 'pattern_counts': {'":': 0, '<': 56, '<?xml version=': 0, '>': 70, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, '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': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '609385', 'license': 'MIT', 'n_tokens_mistral': 4768, 'n_tokens_neox': 4032, 'n_words': 1284, 'path': 'aprendizado-de-maquina-ii/Tarefa_4_3.ipynb', 'repo_name': 'andredarcie/my-data-science-notebooks', 'size': '10639'}