En los últimos tiempos habrás oído hablar de machine learning, deep learning, reinforcement learning, muchas más cosas que contienen la palabra learning y, por supuesto, Big Data. Con los avances en capacidad de cálculo de los últimos años y la popularización de lenguajes de alto nivel, hemos entrado de lleno en la fiebre de hacer que las máquinas aprendan. En esta clase veremos cómo utilizar el paquete scikit-learn
de Python para poder crear modelos predictivos a partir de nuestros datos de una manera rápida y sencilla.
In [1]:
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(42)
En primer lugar vamos a probar con un ejemplo muy sencillo: ajustar una recta a unos datos. Esto difícilmente se puede llamar machine learning, pero nos servirá para ver cómo es la forma de trabajar con scikit-learn
, cómo se entrenan los modelos y cómo se calculan las predicciones.
En primer lugar fabricamos unos datos distribuidos a lo largo de una recta con un poco de ruido:
In [2]:
x = np.random.randn(50)
y = 2.0 * x + 0.8 * np.random.randn(50)
plt.scatter(x, y)
Out[2]:
El proceso para usar scikit-learn
es el siguiente:
features
y variable a predecir y
model.fit
)model.predict
)
In [3]:
from sklearn.linear_model import LinearRegression
In [4]:
model = LinearRegression(fit_intercept=True)
In [5]:
features = x.reshape(-1, 1)
In [6]:
model.fit(features, y)
Out[6]:
In [7]:
y_hat = model.predict(features)
Para calcular el error, en el módulo sklearn.metrics
tenemos varias funciones útiles:
In [8]:
from sklearn import metrics
In [9]:
abs_error = metrics.mean_absolute_error(y, y_hat)
abs_error
Out[9]:
Y ahora predecimos con datos nuevos:
In [10]:
x_new = np.linspace(x.min(), x.max(), 10)
In [11]:
y_pred = model.predict(x_new.reshape(-1, 1))
In [12]:
plt.scatter(x, y)
plt.plot(x_new, y_pred, 'k--')
plt.scatter(x_new, y_pred, marker='x', lw=3, zorder=10)
plt.fill_between(x_new, y_pred + abs_error, y_pred - abs_error, color="C0", alpha=0.3)
Out[12]:
¡Y ya está! Lo básico de scikit-learn
está aquí. Lo próximo será usar diferentes tipos de modelos y examinar con rigor su rendimiento para poder seleccionar el que mejor funcione para nuestros datos.
En aprendizaje automático tenemos dos tipos de problemas:
En función de la naturaleza de nuestro problema, scikit-learn
proporciona una gran variedad de algoritmos que podemos elegir.
En scikit-learn
tenemos disponibles muchos datasets clásicos de ejemplo que podemos utilizar para practicar. Uno de ellos es el dataset MNIST, que consiste en imágenes escaneadas de números escritos a mano por funcionarios de los EEUU. Para cargarlo, importamos la función correspondiente de sklearn.datasets
:
In [13]:
from sklearn.datasets import load_digits
In [14]:
digits = load_digits()
print(digits["DESCR"])
Ya tenemos los datos separados en matriz de características y vector de predicción. En este caso, tendré 64 = 8x8 características (un valor numérico por cada pixel de la imagen) y mi variable a predecir será el número en sí.
Siempre que se hace aprendizaje supervisado, se ha de dividir el dataset en una parte para entrenamiento y otra para test (incluso a veces hay una partición más para validación)
In [25]:
from sklearn.model_selection import train_test_split
In [26]:
# X_train, X_test, Y_train, Y_test =
X_train, X_test, Y_train, Y_test = train_test_split(digits.data, digits.target, train_size=0.75)
In [27]:
# preserve
X_train.shape, Y_train.shape
Out[27]:
In [28]:
# preserve
X_test.shape, Y_test.shape
Out[28]:
Para visualizar estas imágenes tendremos que hacer un .reshape
:
In [29]:
num_ = X_test[42]
label_ = Y_test[42]
num_
Out[29]:
In [30]:
num_.reshape(8, 8).astype(int)
Out[30]:
In [31]:
plt.figure(figsize=(2, 2))
plt.imshow(num_.reshape(8, 8), cmap=plt.cm.gray_r)
Out[31]:
In [32]:
label_
Out[32]:
Ten en cuenta que nosotros sabemos qué número es cada imagen porque somos humanos y podemos leerlas. El ordenador lo sabe porque están etiquetadas, pero ¿qué pasa si viene una imagen nueva? Para eso tendremos que construir un modelo de clasificación. En este caso aplicaremos la regresión logística
In [34]:
from sklearn.linear_model import LogisticRegression
In [37]:
# Inicializamos el modelo
model = LogisticRegression()
In [44]:
# Lo entrenamos
model.fit(X_train, Y_train)
Out[44]:
Y una vez que hemos ajustado el modelo, comprobemos cuáles son sus predicciones usando los mismos datos de entrenamiento:
In [45]:
# Vemos los resultados para los datos de test
predictions = model.predict(X_test)
De nuevo usamos sklearn.metrics
para medir la eficacia del algoritmo:
In [46]:
metrics.accuracy_score(predictions, Y_test)
Out[46]:
¡Parece que hemos acertado prácticamente todas! Más tarde volveremos sobre este porcentaje de éxito, que bien podría ser engañoso. De momento, representemos otra medida de éxito que es la matriz de confusión:
In [48]:
metrics.confusion_matrix(predictions, Y_test)
Out[48]:
In [59]:
plt.imshow(metrics.confusion_matrix(predictions, Y_test), cmap=plt.cm.Blues_r)
Out[59]:
Una vez que hemos visto los dos tipos de problemas supervisados, vamos a ver cómo se trabajan los problemas no supervisados. En primer lugar vamos a fabricar dos nubes de puntos usando la función make_blobs
:
In [61]:
# preserve
# https://github.com/amueller/scipy-2016-sklearn/blob/master/notebooks/05%20Supervised%20Learning%20-%20Classification.ipynb
from sklearn.datasets import make_blobs
In [62]:
# preserve
features, labels = make_blobs(centers=[[6, 0], [2, -1]], random_state=0)
features.shape
Out[62]:
In [63]:
# preserve
plt.scatter(features[:, 0], features[:, 1], c=labels)
Out[63]:
Hemos creado dos grupos y algunos puntos se solapan, pero ¿qué pasaría si no tuviésemos esta información visual? Vamos a emplear un modelo de clustering para agrupar los datos: en este caso KMeans
In [64]:
from sklearn.cluster import KMeans
In [65]:
model = KMeans()
model
Out[65]:
Observa que por defecto tenemos 8 clusters. Veamos qué ocurre:
In [66]:
model.fit(features)
Out[66]:
Ahora no pasamos la información de las etiquetas al algoritmo a la hora de entrenar. En la práctica por supuesto no la tendremos.
In [67]:
centroids = model.cluster_centers_
centroids
Out[67]:
In [68]:
labels_pred = model.predict(features)
Y ahora preparamos el código para representar todas las regiones:
In [77]:
# preserve
xmin, xmax = features[:, 0].min(), features[:, 0].max()
ymin, ymax = features[:, 1].min(), features[:, 1].max()
xx, yy = np.meshgrid(
np.linspace(xmin, xmax),
np.linspace(ymin, ymax)
)
mesh = np.c_[xx.ravel(), yy.ravel()]
mesh
Out[77]:
In [78]:
Z = model.predict(mesh)
In [80]:
# http://pybonacci.org/2015/01/14/introduccion-a-machine-learning-con-python-parte-1/
plt.pcolormesh(xx, yy, Z.reshape(xx.shape))
plt.scatter(features[:, 0], features[:, 1], marker='x', color='k')
plt.scatter(centroids[:, 0], centroids[:, 1], marker='+', color='r', lw=2)
Out[80]:
Si lo metemos todo en una función interactiva:
In [81]:
from ipywidgets import interact
In [82]:
# preseve
@interact(n=(2, 6))
def cluster(n=3):
model = KMeans(n_clusters=n)
model.fit(features)
labels_pred = model.predict(features)
centroids = model.cluster_centers_
Z = model.predict(mesh)
plt.pcolormesh(xx, yy, Z.reshape(xx.shape))
plt.scatter(features[:, 0], features[:, 1], marker='x', color='k')
plt.scatter(centroids[:, 0], centroids[:, 1], marker='+', color='r', lw=2)
plt.show()
Vamos a rescatar nuestro dataset de los dígitos y tratar de visualizarlo en dos dimensiones, lo que se conoce como reducción de dimensionalidad.
In [43]:
from sklearn.manifold import Isomap
In [44]:
model = Isomap(n_components=2)
In [45]:
model.fit(digits.data)
Out[45]:
Y ahora proyectamos los datos usando .transform
:
In [46]:
digits_proj = model.transform(digits.data)
In [47]:
plt.scatter(digits_proj[:, 0], digits_proj[:, 1],
c=digits.target, cmap=plt.cm.Vega10, alpha=0.5)
plt.colorbar()
Out[47]:
load_iris
) utilizando las funciones que tienes más abajo. ¿Hay alguna forma clara de separar las tres especies de flores?features
y vector de etiquetas labels
. Conviértelos a arrays de NumPy usando .as_matrix()
.sklearn.manifold.Isomap
o sklearn.decomposition.PCA
y usa un algoritmo de clustering con 3 clusters. ¿Se parecen los clusters que aparecen a los grupos originales?
In [84]:
# preserve
import pandas as pd
def load_iris_df():
from sklearn.datasets import load_iris
iris = load_iris()
features, labels = iris.data, iris.target
df = pd.DataFrame(features, columns=iris.feature_names)
df["species"] = pd.Categorical.from_codes(iris.target, categories=iris.target_names)
#df = df.replace({'species': {0: iris.target_names[0], 1: iris.target_names[1], 2: iris.target_names[2]}})
return df
iris_df = load_iris_df()
In [85]:
# preserve
iris_df.head()
Out[85]:
In [88]:
# preserve
_ = pd.tools.plotting.scatter_matrix(iris_df, c=iris_df["species"].cat.codes, figsize=(10, 10))