<jupyter_start><jupyter_text>1. PerceptronEmpezamos cargando librerías<jupyter_code>import numpy as np
import pandas as pd
import seaborn as sns

import matplotlib.pyplot as plt
%matplotlib inline<jupyter_output><empty_output><jupyter_text>Cargamos datos. Utilizaremos el dataset de pingüinos de seaborn:<jupyter_code>df = sns.load_dataset("penguins")

# Limpiamos un poco los datos
df.dropna(inplace=True)
cleanup_nums = {"species": {"Adelie": 0,
                            "Chinstrap": 1,
                            "Gentoo": 2},
               "sex": {"Male": 0,
                       "Female": 1}}
df.replace(cleanup_nums, inplace=True)
df = pd.get_dummies(df)

df.head()<jupyter_output><empty_output><jupyter_text>Dividimos en train test<jupyter_code>from sklearn.model_selection import train_test_split

X = df.iloc[:, 1:]
y = df.iloc[:, 0]

X_train, X_test, y_train, y_test = train_test_split(X,
                                                    y,
                                                    test_size=0.2,
                                                    random_state=42)
print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)<jupyter_output>(266, 9)
(67, 9)
(266,)
(67,)<jupyter_text>Vamos a probar un Perceptrón<jupyter_code>from sklearn.linear_model import Perceptron

per_clf = Perceptron()
per_clf.fit(X_train, y_train)
per_clf.score(X_test, y_test)
from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression(max_iter=500)
log_reg.fit(X_train, y_train)
log_reg.score(X_test, y_test)<jupyter_output>C:\Users\TheBridge\anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py:763: ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.

Increase the number of iterations (max_iter) or scale the data as shown in:
    https://scikit-learn.org/stable/modules/preprocessing.html
Please also refer to the documentation for alternative solver options:
    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression
  n_iter_i = _check_optimize_result(<jupyter_text>Probemos a estandarizar:<jupyter_code>from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(X_train)
X_train_s = sc.transform(X_train)
X_test_s = sc.transform(X_test)

per_clf = Perceptron()
per_clf.fit(X_train_s, y_train)
per_clf.score(X_test_s, y_test)
from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression(max_iter=500)
log_reg.fit(X_train_s, y_train)
log_reg.score(X_test_s, y_test)<jupyter_output><empty_output><jupyter_text>EJEMPLO no lineal:<jupyter_code>x_nl = np.linspace(-10, 10, 1000)
y_nl = (x_nl**2) > 25

plt.plot(x_nl, (x_nl**2)/100, 'b--', label='x**2')
plt.plot(x_nl, y_nl, 'r', label='y')
plt.legend()
X_nl = pd.DataFrame({'X': x_nl})
Y_nl = pd.Series(y_nl)

X_train2, X_test2, y_train2, y_test2 = train_test_split(X_nl,
                                                        Y_nl,
                                                        test_size=0.2,
                                                        random_state=42)

from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(X_train2)
X_train_s2 = sc.transform(X_train2)
X_test_s2 = sc.transform(X_test2)

per_clf = Perceptron()
per_clf.fit(X_train_s2, y_train2)
per_clf.score(X_test_s2, y_test2)
log_reg = LogisticRegression(max_iter=500)
log_reg.fit(X_train_s2, y_train2)
log_reg.score(X_test_s2, y_test2)<jupyter_output><empty_output><jupyter_text>En este caso, en ambos modelos, parece que la estandarización es la clave, y es que ambos modelos son muy dependientes de las escalas de los datos.Aun así, si nos fijamos en el comportamiento base del perceptrón, parece que no es muy bueno (pese a que con ayuda del StandardScaler mejora mucho). Y eso que estamos hablando de un modelo muy sencillito. Por lo tanto, parece razonable estudiar configuraciones más complejas:  2. Multi Layer Perceptron<jupyter_code>from sklearn.neural_network import MLPClassifier

mlp = MLPClassifier(max_iter = 500)
mlp.fit(X_train, y_train)

print(mlp.score(X_train, y_train))
print(mlp.score(X_test, y_test))<jupyter_output>0.5375939849624061
0.5223880597014925<jupyter_text>Probemos otra configuración. Es posible crear una red neuronal desde la propia función de MLPClassifier()<jupyter_code>mlp = MLPClassifier(max_iter = 500,
                   activation='tanh',
                   hidden_layer_sizes = (150, 150, 150))

mlp.fit(X_train, y_train)

print(mlp.score(X_train, y_train))
print(mlp.score(X_test, y_test))<jupyter_output>0.6541353383458647
0.6865671641791045<jupyter_text>Bueno, parece que nuestra red de perceptrones mejora mucho el perceptrón por sí solo, pero seguimos obteniendo algo que dista mucho de lo que queremos. Y es que, al igual que acabamos de ver para el perceptrón, las redes multicapa de perceptrones utilizan descenso del gradiente, y por tanto son muy sensibles al escalado.Estandarizamos para el siguiente ejemplo:<jupyter_code>from sklearn.preprocessing import StandardScaler

sc = StandardScaler()
sc.fit(X_train)
X_train_s = sc.transform(X_train)
X_test_s = sc.transform(X_test)

per_clf = Perceptron()
per_clf.fit(X_train_s, y_train)
print(per_clf.score(X_train_s, y_train))
print(per_clf.score(X_test_s, y_test))
log_reg = LogisticRegression(max_iter=500)
log_reg.fit(X_train_s, y_train)
print(log_reg.score(X_train_s, y_train))
print(log_reg.score(X_test_s, y_test))
from sklearn.neural_network import MLPClassifier
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(X_train)
X_train_scal =scaler.transform(X_train)
X_test_scal =scaler.transform(X_test)

mlp = MLPClassifier(max_iter=500)
mlp.fit(X_train_scal, y_train)
print(mlp.score(X_train_scal, y_train))
print(mlp.score(X_test_scal, y_test))<jupyter_output>1.0
1.0<jupyter_text>Evidentemente, como estamos con unos datos muy preparados para este ejemplo, al estandarizar nos ofrecen un resultado perfecto, como podíamos esperar tras ver el ejemplo anterior.De este modo, se pone de manifiesto la importancia del escalado en este tipo de problemas, ya que son muy dependientes de las relaciones entre variables. Por ello, será muy importante trabajar con el StandardScaler cuando hablemos de modelos lineales, ya que tanto el ``Perceptrón``, como la ``Regresión Logística`` o la configuración ``MLP`` consiguen un resultado muy bueno tras su aplicación.Pero bueno, realmente no hemos visto nada que nos mejore una barbaridad, así que hagamos un ejercicio donde pongamos las cosas (un poquito) más difíciles a nuestro modelo:  EJERCICIOUtiliza los datos no lineales del ejemplo del perceptrón y la regresión lineal donde daban malos resultados y comprueba qué pasa con la MLP que acabamos de ver:Prueba tanto directamente como aplicando el escalado:<jupyter_code>x_nl = np.linspace(-10, 10, 1000)
y_nl = (x_nl**2) > 25

plt.plot(x_nl, (x_nl**2)/100, 'b--', label='x**2')
plt.plot(x_nl, y_nl, 'r', label='y')
plt.legend()

X_nl = pd.DataFrame({'X': x_nl})
Y_nl = pd.Series(y_nl)

X_train2, X_test2, y_train2, y_test2 = train_test_split(X_nl,
                                                        Y_nl,
                                                        test_size=0.2,
                                                        random_state=42)

from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(X_train2)
X_train_s2 = sc.transform(X_train2)
X_test_s2 = sc.transform(X_test2)

mlp = MLPClassifier(max_iter=500)
mlp.fit(X_train_s2, y_train2)
print(mlp.score(X_train_s2, y_train2))
print(mlp.score(X_test_s2, y_test2))
preds = mlp.predict(X_test_s2)

plt.plot(preds[:100], 'bo', alpha = 0.3)
plt.plot(y_test2.values[:100], 'ro', alpha = 0.3)
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(X_train2)
X_train_s2 = sc.transform(X_train2)
X_test_s2 = sc.transform(X_test2)

mlp = MLPClassifier(max_iter=5000)
mlp.fit(X_train_s2, y_train2)
print(mlp.score(X_train2, y_train2))
print(mlp.score(X_test2, y_test2))<jupyter_output>0.5975
0.54<jupyter_text>Ejercicio En este caso, vamos a ver cómo se comportan nuestros modelos con la clasificación de medicamentos. Para ello, leeremos un dataset con algunas columnas categóricas, que deberemos convertir a numéricas de la forma que creamos conveniente.Utiliza un reparto train/test de 70/30.<jupyter_code>df = pd.read_csv("../drug200.csv")
df
df['Drug'].value_counts()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09558649988199197, 'fraction_numerical': 0.029383998111871607, 'mean_word_length': 4.300187617260788, 'pattern_counts': {'":': 7, '<': 39, '<?xml version=': 0, '>': 41, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '426121', 'license': 'MIT', 'n_tokens_mistral': 3287, 'n_tokens_neox': 3105, 'n_words': 716, 'path': 'Bloque 3 - Machine Learning/05_Deep_Learning/1-Intro Deep Learning/01_Perceptron & MLP.ipynb', 'repo_name': 'franciscocanon-thebridge/bootcamp_thebridge_PTSep20', 'size': '8474'}