In [4]:
"""
IPython Notebook v4.0 para python 2.7
Librerías adicionales: numpy, matplotlib
Contenido bajo licencia CC-BY 4.0. Código bajo licencia MIT. (c) Sebastian Flores.
"""
# Configuracion para recargar módulos y librerías
%reload_ext autoreload
%autoreload 2
%matplotlib inline
from IPython.core.display import HTML
HTML(open("style/mat281.css", "r").read())
Out[4]:
Buscaremos ilustrar los distintos algoritmos con datos reales. Un conjunto de datos interesante y versatil es el Iris Dataset, que puede utilizarse para clustering, regresión y clasificación.
Fue utilizado por Ronald Fisher en su artículo "The use of multiple measurements in taxonomic problems" (1936).
El conjunto de datos consiste en 50 muestras de 3 especies de Iris (Iris setosa, Iris virginica y Iris versicolor). Para cada flor, se midieron 4 características: largo y ancho de los petalos, y largo y ancho de los sépalos, en centímetros.
In [5]:
from sklearn import datasets
import matplotlib.pyplot as plt
iris = datasets.load_iris()
def plot(dataset, ax, i, j):
ax.scatter(dataset.data[:,i], dataset.data[:,j], c=dataset.target, s=50)
ax.set_xlabel(dataset.feature_names[i], fontsize=20)
ax.set_ylabel(dataset.feature_names[j], fontsize=20)
# row and column sharing
f, ((ax1, ax2), (ax3, ax4), (ax5,ax6)) = plt.subplots(3, 2, figsize=(16,8))
plot(iris, ax1, 0, 1)
plot(iris, ax2, 0, 2)
plot(iris, ax3, 0, 3)
plot(iris, ax4, 1, 2)
plot(iris, ax5, 1, 3)
plot(iris, ax6, 2, 3)
f.tight_layout()
plt.show()
Input: set $X$ de $N$ datos $x=(x_1, ..., x_n)$ y un meta-parámetro $k$ con el número de clusters a crear.
Output: Set de $k$ centroides de clusters ($\mu_l$) y una etiquetación de cada dato $x$ en $X$ indicando a qué cluster pertenece.
$x_i$ y $\mu_l$ son vectores en $\mathcal{R}^m$.
La pertenencia es única. Todos los puntos dentro de un cluster se encuentran mas cercanos en distancia al centroide de su cluster que al centroide de otro cluster.
Matemáticamente: \begin{align*} \textrm{Minimizar } \sum_{l=1}^k \sum_{x_n \in C_l} ||x_n - \mu_l ||^2 \textrm{ respecto a } C_l, \mu_l. \end{align*} Donde $C_l$ es el cluster l-ésimo.
El problema anterior es NP-hard (imposible de resolver en tiempo polinomial, del tipo más difícil de los probleams NP).
In [11]:
from mat281_code import iplot
iplot.kmeans(N_points=100, n_clusters=4)
In [12]:
import numpy as np
from scipy.linalg import norm
def find_centers(X, k, seed=None):
if seed is None:
seed = np.random.randint(10000000)
np.random.seed(seed)
# Initialize to K random centers
old_centroids = random_centers(X, k)
new_centroids = random_centers(X, k)
while not has_converged(new_centroids, old_centroids):
old_centroids = new_centroids
# Assign all points in X to clusters
clusters = cluster_points(X, old_centroids)
# Reevaluate centers
new_centroids = reevaluate_centers(X, clusters, k)
return (new_centroids, clusters)
In [13]:
def random_centers(X, k):
index = np.random.randint(0, X.shape[0], k)
return X[index, :]
In [14]:
def has_converged(new_mu, old_mu, tol=1E-6):
num = norm(np.array(new_mu)-np.array(old_mu))
den = norm(new_mu)
rel_error= num/den
return rel_error < tol
In [15]:
def cluster_points(X, centroids):
clusters = []
for i, x in enumerate(X):
distances = np.array([norm(x-cj) for cj in centroids])
clusters.append( distances.argmin())
return np.array(clusters)
In [17]:
def reevaluate_centers(X, clusters, k):
centroids = []
for j in range(k):
cj = X[clusters==j,:].mean(axis=0)
centroids.append(cj)
return centroids
In [23]:
from mat281_code import gendata
from mat281_code import plot
from mat281_code import kmeans
X = gendata.init_blobs(1000, 4, seed=40)
ax = plot.data(X)
centroids, clusters = kmeans.find_centers(X, k=4)
plot.clusters(X, centroids, clusters)
In [28]:
from mat281_code import gendata
from mat281_code import plot
from sklearn.cluster import KMeans
X = gendata.init_blobs(10000, 6, seed=43)
plot.data(X)
kmeans = KMeans(n_clusters=6)
kmeans.fit(X)
centroids = kmeans.cluster_centers_
clusters = kmeans.labels_
plot.clusters(X, centroids, clusters)
In [35]:
import numpy as np
from sklearn import datasets
from sklearn.cluster import KMeans
from sklearn.metrics import confusion_matrix
# Parameters
n_clusters = 8
# Loading the data
iris = datasets.load_iris()
X = iris.data
y_true = iris.target
# Running the algorithm
kmeans = KMeans(n_clusters)
kmeans.fit(X)
y_pred = kmeans.labels_
# Show the classificacion report
cm = confusion_matrix(y_true, y_pred)
print cm
print (cm.sum() - np.diag(cm).sum() ) / float(cm.sum()) # 16/100