MachineLearning Python V02
MachineLearning Python V02
K-MEANS 15!
IMPLEMENTACIÓN!DEL!K.MEANS! 19!
K.MEANS!CON!SCIKIT.LEARN! 28!
EXPECTATION-MAXIMIZATION (EM) 35!
IMPLEMENTACIÓN!DEL!EXPECTATION.MAXIMIZATION! 41!
EXPECTATION.MAXIMIZATION!(GAUSSIAN!MIXTURE!MODELS)!CON!SCIKIT.LEARN! 51!
SELECCIÓN DEL NÚMERO ÓPTIMO DE CLUSTERS 59!
MÉTODO!DEL!CODO!(ELBOW!METHOD)! 60!
DENDROGRAMAS! 63!
GAP! 66!
BIBLIOGRAFÍA 70!
Para que estos sistemas puedan aprender por ellos mismos, se utilizan una serie de
técnicas y algoritmos capaces de crear modelos predictivos, patrones de comportamiento,
etc. Aunque no existe en la bibliografía actual un listado concreto y acotado de aquellas
técnicas y algoritmos que se enmarcan dentro de la rama del ML (aunque hay algunas
técnicas que claramente son propias de dicha área), si que podemos decir que en el área
del ML encaja todo proceso de resolución de problemas, basados más o menos
explícitamente en una aplicación rigurosa de la teoría de la decisión estadística; por tanto,
es muy normal que el área del ML se solape con el área de la estadística. En ML; a diferencia
de la estadística, se centra en el estudio de la complejidad computacional de los problemas,
ya que gran parte de estos son de la clase NP-completo (o NP-hard) y por tanto el reto del
ML está en diseñar soluciones factibles para este tipo de problemas.
Tom Michell (1998): Un programa se dice que aprende de una experiencia ‘E’
con respecto a alguna tarea ‘T’ y alguna medida de rendimiento ‘R’, si su
rendimiento en ‘T’ medida por ‘R’, mejora con la experiencia ‘E’.
Dos ejemplos de sistemas expertos creados tras aplicar alguna/s técnica/s de ML,
serían los siguientes: uno, un sistema experto en predicción de quinielas (clasificación), que
pasándole el nombre del equipo local y visitante, devuelve como resultado una de las tres
opciones de la quiniela (1, X, 2); y otro un sistema experto en el cálculo de calorías
quemadas (regresión) al hacer carrera continua (running), en el que pasándole como
entrada el peso de la persona, el tiempo de carrera y la velocidad, devuelva como resultado
el número de calorías quemadas (0 ≤ calorías < ∞).
Como hemos visto, estos sistemas tienen dos formas de proporcionar un resultado:
uno; la clasificación, que devuelve como salida un conjunto finito de resultados;
generalmente pequeño, (y={0,1}, y={1,X,2}, y={si,no}) y otro; la regresión, que
devuelve como salida un valor arbitrario (un número real, un vector de números reales,
cadenas de símbolos, etc.).
Regresión: Tanto los datos de entrada como los de salida, pertenecen a dominios
(!, #) arbitrarios. Un ejemplo seria ! = # = ℝ, siendo el modelo resultante o la
hipótesis una función &: ℝ → ℝ
Visto el tipo de sistemas expertos que queremos conseguir tras aplicar alguna/s
técnica/s de ML, tenemos que ver como aprenden estos sistemas para obtener esa función
de clasificación o regresión, que en adelante la denominaremos “hipótesis”.
Para que los sistemas aprendan, se ha de tener un conjunto de datos (o data set)
de aprendizaje o entrenamiento (datos de entrada /0 ∈ 0! y de salida 20 ∈ 0# ) que son
utilizados para obtener una hipótesis (modelo o función & ∶ 0! → #) que generalice esos
datos adecuadamente. Cuando se habla de “generalizar”, se habla de predecir la salida a
partir de nuevos datos de entrada (datos de test) distintos a los datos de entrenamiento.
Overfitting y Underfitting
Aunque esto sería un resumen de los datos que hay en el conjunto de datos de
entrenamiento, una persona (sea o no experta en fútbol) y viendo los datos de
entrenamiento, podría predecir que el resultado de este partido sería un “1” (gana el FC
Barcelona) ya que el FC Barcelona es: uno de los equipos más potentes, gana la mayoría
de los partidos, se enfrenta a un equipo que pierde más partidos de los que gana y además
juega en su estadio (60% de los partidos los ganan los equipo locales). Aunque los
algoritmos de aprendizaje en ML no tienen la capacidad de hacer estos razonamientos (ya
que estos se hacen de forma matemática) si que se espera que el resultado sea coherente
y similar al que haría un humano. Pero, ¿Que resultado arrojaría el sistema si se ha
producido overfitting o underfitting?:
1.! Overfitting ("FC Barcelona-Rayo Vallecano = Victoria del Rayo Vallecano”): Como
en el conjunto de datos de entrenamiento se ha dado la casualidad de que solo hay
3 datos de enfrentamientos entre estos equipos y son de victorias de Rayo Vallecano;
ajustándome a los datos de entrenamiento, digo que gana el Rayo Vallecano porque
es la información de la que se dispone.
3.! Underfitting ("Rayo Vallecano-FC Barcelona = Victoria del Rayo Vallecano”): Por
analogía con el caso anterior; al ser el Rayo Vallecano el equipo local, ganaría el Rayo
Vallecano.
Veamos por ejemplo para el caso de la regresión, el error que se cometería si nos
llegase un nuevo dato de entrada (punto rojo), para cada uno de las funciones obtenidas:
Ilustración 11: Error Overfitting Ilustración 12: Error de un ajuste Ilustración 13: Error Underfitting
correcto
Se puede apreciar como el error cometido con un dato de test, es mayor en el caso
en el que se produce overfitting y underfitting, y es menor en el caso en el que se ha
generalizado de forma correcta, aunque evidentemente tiene un pequeño error.
Dependiendo de cómo sean los datos de los que dispongamos para entrenar al
sistema, podemos aplicar un tipo de aprendizaje u otro. A continuación se enumeran y
explican los tipos de aprendizaje más comunes:
5.- Aprendizaje on-line: En este tipo de aprendizaje no hay una distinción concreta entre
la fase de test y de entrenamiento. El sistema aprende (normalmente desde cero) mediante
el propio proceso de predicción en el que hay una supervisión humana que consiste en
validar o corregir cada salida en función de la entrada.
6.- Aprendizaje por refuerzo: Tipo de aprendizaje híbrido entre el aprendizaje on-line y
aprendizaje semi-supervisado en el que la supervisión es incompleta; normalmente una
información del tipo {si,no}, {0,1}, {premio,castigo}. Es un tipo de aprendizaje que se
basa en el “argumentum ad baculum”, utilizado normalmente en la educación de los
animales.
Para evaluar las hipótesis obtenidas tras la aplicación de alguna de las técnicas de
ML, es necesario disponer de un conjunto de datos (etiquetados o no) para generar la mejor
de las hipótesis posibles y minimizar el error empírico. Dado un conjunto de datos, podemos
1.- Resustitución: Es un método muy optimista en el que todos los datos disponibles se
utilizan como datos de test y de entrenamiento.
2.- Partición (Hold Out) : Este método divide los datos en dos subconjuntos: uno de
entrenamiento y uno de test. El problema que tiene este método es que se desaprovechan
los datos de test para la obtención de la hipótesis.
3.- Validación cruzada (Cross Validation) : Este método divide los datos aleatoriamente
en ‘N’ bloques. Cada bloque se utiliza como test para un sistema entrenado por el resto de
bloques. El inconveniente de este método es que reduce el número de datos de
entrenamiento cuando el número de datos de cada bloque es grande.
4.- Exclusión individual (Leaving one out) : Este método utiliza cada dato individual
como dato único de test de un sistema entrenado con todos los datos excepto el de test. Es
similar al método de la validación cruzada, pero en este caso el coste computacional es muy
grande por la cantidad de fases de aprendizaje que se deben de realizar.
Supongamos el siguiente caso de ejemplo: Tenemos un data set (DS1) con el color
de pelo de un conjunto de personas. Como entrada tenemos el color en RGB del pelo de
cada persona y como salida un conjunto finito de etiquetas {Moreno, Rubio, Castaño,
Canoso}. Por otro lado tenemos otro data set (DS2) con el color del pelo en RBG de otro
conjunto de personas, pero en este caso no tenemos como salida una etiqueta que nos diga
si el individuo es Moreno, Rubio, Castaño o Canoso. Para ambos casos queremos generar
En este ejemplo podemos apreciar como nos divide los individuos en 4 grupos, en
función de su color de pelo y como podemos ser capaces posteriormente de identificar y
etiquetar a cada grupo de personas.
En resumen, las técnicas de Clustering son apropiadas para los casos de aprendizaje
no supervisado en los que se quiere agrupar y tener conocimiento a un alto nivel de cómo
se han generado los datos y como están organizados, sin tener conocimiento a priori de
estos.
K-means
J
4
F<;96@B = /G − 0I
GKL
El algoritmo de los K-means tienen como objetivo elegir ‘K’ centroides que reduzcan
al mínimo la inercia:
X
4
argmin /G − 0 IT
S
TKY UV ∈0SW
Z[ !, I = 0 /G0 − 0 IG 4 0
GKY
•! Actualización: Calcula los nuevos centroides, haciendo la media de los objetos que
forman el Cluster.
J
1
I= 0 /T 0
-
TKY
1.! Inicialización de los Clusters: Para ello cogemos al azar 3 puntos del data set y
los asignamos a un Cluster. Como cada Cluster solo tiene un punto, será ese punto
el centroide del Cluster:
Ilustración 16: Asignación 1 de puntos a los Clusters Ilustración 17: Cálculo 1 de nuevos centroides
Ilustración 18: Asignación 2 de puntos a los Clusters Ilustración 19: Cálculo 2 de nuevos centroides
Definido el funcionamiento del algoritmo paso por paso y con un ejemplo, pasamos
a mostrarlo en pseudocódigo:
K = num_clusters
for i in range(dataset):
2
AX ∶= argmin /@ −0I]
for j in range(K):
Y J
IT : = 0
J GKY /G 0
En los dos siguientes puntos: Implementación del K-means y K-means con scikit-
learn, se va a mostrar la implementación del K-means y el uso de la librería scikit-learn
para la resolución de un problema de Clustering con el algoritmo del K-means
respectivamente, cuyo código se puede obtener en el siguiente repositorio:
https://github.com/RicardoMoya/KMeans_Python
El código que se encuentra en este repositorio hace uso de las librerías de numpy,
matplotlib, scipy y scikit-learn. Para descargar e instalar (o actualizar a la última versión
Para implementar el K-means, vamos a tener objetos que serán representados como
puntos en 2D, por tanto implementaremos una clase Punto (Point.py) para representar los
objetos. Por otro lado se implementa una clase Cluster (Cluster.py) para representar a los
Clusters y que estará compuesta por un conjunto de objetos de la clase Punto. Por último
tendremos un script (KMeans.py) en el que estará implementado del K-means con sus dos
pasos de asignación y actualización para ‘k’ Clusters. A continuación se muestra a un alto
nivel de abstracción el diagrama de clases de la implementación propuesta del K-means:
Los data sets a utilizar en este ejemplo (que se encuentran dentro de la carpeta
dataSet) van a ser ficheros de texto en los que en cada línea van a estar las coordenadas
1.857611652::2.114033851
2.34822574::1.58264984
1.998326848::4.118143019
1.714362835::2.468639613
1.656134484::1.909955747
Esto quiere decir que el primer punto va a estar posicionado en las coordenadas
{1.85,2.11} y el segundo punto en las coordenadas {2.34,1.58}.
Para los ejemplos disponemos de 4 data sets con las siguientes características:
Nº Clusters Centroides
Nombre Nº Puntos
teóricos teóricos
{2,2}
Visto el diagrama de clases y la estructura de los date sets a utilizar, vamos a pasar
a mostrar la implementación de la clases Punto (Point.py). A esta clase se le va a pasar en
el constructor un “numpy array” con las coordenadas del punto y va a tener como atributos
esa coordenada y las dimensiones de la misma, que para el ejemplo que vamos a mostrar
será de 2:
def __repr__(self):
return 'Coordinates: ' + str(self.coordinates) + \
' -> Dimension: ' + str(self.dimension)
Por otro lado vamos a tener la clase Cluster (Cluster.py) que se le va a pasar en el
constructor una lista de puntos que van a ser los que formen el Cluster. Esta clase va a
tener como atributos la lista de puntos del Cluster (points), la dimensión de los puntos
(dimension), el centroide del Cluster (centroid) y un atributo (converge) que nos va a indicar
si el centroide es igual (por tanto converge) que el calculado en el paso de actualización de
la iteración anterior. Con la lista de puntos que van a formar el Cluster, hacemos las
comprobaciones pertinentes (que el Cluster tenga por lo menos un punto y que todos los
puntos sean de la misma dimensión), para no lanzar ninguna excepción. Veamos a
continuación el constructor de esta clase:
import numpy as np
class Cluster:
# Check that all elements of the cluster have the same dimension
for p in points:
if p.dimension != self.dimension:
raise Exception(
"Point %s has dimension %d different with %d from the rest "
"of points") % (p, len(p), self.dimension)
# Calculate Centroid
self.centroid = self.calculate_centroid()
self.converge = False
sum_coordinates = np.zeros(self.dimension)
for p in self.points:
for i, x in enumerate(p.coordinates):
sum_coordinates[i] += x
NOTA: La implementación de este método puede ser optimizada paralelizando el cálculo del centroide con threads (hilos).
Por razones didácticas y por legibilidad y claridad del código no se ha optimizado este método.
old_centroid = self.centroid
self.points = points
self.centroid = self.calculate_centroid()
self.converge = np.array_equal(old_centroid, self.centroid)
Una vez explicadas las Clases Punto y Cluster que necesitamos para estructurar la
información, vamos a pasar a explicar la implementación del K-means propiamente dicha.
Esta implementación esta en el script KMeans.py que mostramos a continuación y que
posteriormente vamos a explicar cada fragmento de código relevante:
import random
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import distance
from Point import Point
from Cluster import Cluster
DATASET1 = "./dataSet/DS_3Clusters_999Points.txt"
DATASET2 = "./dataSet/DS2_3Clusters_999Points.txt"
DATASET3 = "./dataSet/DS_5Clusters_10000Points.txt"
DATASET4 = "./dataSet/DS_7Clusters_100000Points.txt"
NUM_CLUSTERS = 3
ITERATIONS = 1000
COLORS = ['red', 'blue', 'green', 'yellow', 'gray', 'pink', 'violet', 'brown',
'cyan', 'magenta']
def dataset_to_list_points(dir_dataset):
"""
22 MACHINE LEARNING (en Python), con ejemplos
Read a txt file with a set of points and return a list of objects Point
:param dir_dataset:
"""
points = list()
with open(dir_dataset, 'rt') as reader:
for point in reader:
points.append(Point(np.asarray(map(float, point.split("::")))))
return points
def print_results(clusters):
print '\n\nFINAL RESULT:'
for i, c in enumerate(clusters):
print '\tCluster %d' % (i + 1)
print '\t\tNumber Points in Cluster %d' % len(c.points)
print '\t\tCentroid: %s' % str(c.centroid)
def plot_results(clusters):
plt.plot()
for i, c in enumerate(clusters):
# plot points
x, y = zip(*[p.coordinates for p in c.points])
plt.plot(x, y, linestyle='None', color=COLORS[i], marker='.')
# plot centroids
plt.plot(c.centroid[0], c.centroid[1], 'o', color=COLORS[i],
markeredgecolor='k', markersize=10)
plt.show()
converge = False
it_counter = 0
if __name__ == '__main__':
k_means(DATASET1, NUM_CLUSTERS, ITERATIONS)
if __name__ == '__main__':
k_means(DATASET1, NUM_CLUSTERS, ITERATIONS)
points = dataset_to_list_points(dataset)
converge = False
it_counter = 0
while (not converge) and (it_counter < iterations):
# ASIGNACION
for p in points:
i_cluster = get_nearest_cluster(clusters, p)
new_points_cluster[i_cluster].append(p)
# ACTUALIZACIÓN
for i, c in enumerate(clusters):
c.update_cluster(new_points_cluster[i])
# ¿CONVERGE?
converge = [c.converge for c in clusters].count(False) == 0
# Incrementamos el contador
it_counter += 1
new_points_cluster = [[] for i in range(num_clusters)]
print_clusters_status(it_counter, clusters)
print_results(clusters)
plot_results(clusters)
NOTA: La implementación de los pasos de Asignación y Actualización pueden ser optimizados paralelizando los cálculos con
threads (hilos). Por razones didácticas y por legibilidad y claridad del código no se ha optimizado esta parte.
1.! Elección de 3 puntos al azar para inicializar los Clusters. Como cada Cluster será
inicializado con un solo punto, ese será su centroide:
CLUSTER 2:
Centroid: [4.56416743, 5.372954912]
Dimension: 2
Puntos: [ 4.56416743 5.37295491]
CLUSTER 3:
Centroid: [2.580421023, 2.887390198]
Dimension: 2
Puntos: [ 2.58042102 2.8873902 ]
ITERATION 1
Centroid Cluster 1: [1.0075506731128203, 6.89332954671282]
Centroid Cluster 2: [4.965693151866954, 4.989117886197427]
Centroid Cluster 3: [2.097612910089318, 2.0566417310823106]
3.! Iteración 2:
ITERATION 2
Centroid Cluster 1: [1.0110313303520406, 6.881641713040817]
Centroid Cluster 2: [4.902010815637452, 4.87296486188048]
Centroid Cluster 3: [2.0337844236032625, 2.0092213794438396]
4.! Iteración 3:
ITERATION 3
Centroid Cluster 1: [1.0110313303520406, 6.881641713040817]
Centroid Cluster 2: [4.888163414869566, 4.864725364043481]
Centroid Cluster 3: [2.0297243138036376, 2.002597935785454]
5.! Iteración 4: Convergen los centroides, teniendo los mismos valores que en la
iteración 3.
ITERATION 4
Centroid Cluster 1: [1.0110313303520406, 6.881641713040817]
Centroid Cluster 2: [4.888163414869566, 4.864725364043481]
Centroid Cluster 3: [2.0297243138036376, 2.002597935785454]
FINAL RESULT:
Cluster 1
Number Points in Cluster 196
Centroid: [1.0110313303520406, 6.881641713040817]
Ilustración 22: Resultado final para el Data Set 1 con 999 puntos y 3 Clusters
Ilustración 23: Resultado final para el Data Set 2 con 999 puntos y 3 Clusters
Ilustración 25: Resultado final para el Data Set 4 con 100000 puntos y 7 Clusters
1.! n_clusters: Indicaremos el número de Clusters que queremos obtener para agrupar
los objetos del data set.
2.! max_iter: número máximo de ejecuciones de los pasos de asignación y actualización
a realizar en el caso de que no converjan los centroides
De forma opcional podemos definir una serie de parámetros con los valores que
consideremos, siendo los más prácticos (según la opinión del autor) los siguientes:
Una vez construido el objeto de la clase KMeans, debemos de llamar a los métodos
pertinentes para que nos agrupe los objetos del data set en los diferentes Clusters. En este
caso y para el ejemplo que a continuación mostramos, vamos a llamar el método fit(x) al
que pasamos como parámetro una lista de puntos (cada punto en un numpy array) y nos
devuelve los centroides de los Clusters (en el atributo cluster_centers_), una lista
alineada con la lista de puntos que le pasamos en el que nos dice a que Cluster pertenece
cada punto (en el atributo labels_) y la inercia (en el atributo inertia_).
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
# Constant
DATASET1 = "./dataSet/DS_3Clusters_999Points.txt"
DATASET2 = "./dataSet/DS2_3Clusters_999Points.txt"
DATASET3 = "./dataSet/DS_5Clusters_10000Points.txt"
DATASET4 = "./dataSet/DS_7Clusters_100000Points.txt"
NUM_CLUSTERS = 3
MAX_ITERATIONS = 10
INITIALIZE_CLUSTERS = ['k-means++', 'random']
CONVERGENCE_TOLERANCE = 0.001
NUM_THREADS = 8
COLORS = ['red', 'blue', 'green', 'yellow', 'gray', 'pink', 'violet', 'brown',
'cyan', 'magenta']
def dataset_to_list_points(dir_dataset):
"""
Read a txt file with a set of points and return a list of objects Point
:param dir_dataset: path file
"""
points = list()
with open(dir_dataset, 'rt') as reader:
for point in reader:
points.append(np.asarray(map(float, point.split("::"))))
return points
# Object KMeans
kmeans = KMeans(n_clusters=num_clusters, max_iter=max_iterations,
init=init_cluster, tol=tolerance, n_jobs=num_threads)
# Calculate Kmeans
kmeans.fit(points)
if __name__ == '__main__':
k_means(DATASET1, NUM_CLUSTERS, MAX_ITERATIONS, INITIALIZE_CLUSTERS[0],
CONVERGENCE_TOLERANCE, NUM_THREADS)
# Constant
DATASET1 = "./dataSet/DS_3Clusters_999Points.txt"
NUM_CLUSTERS = 3
MAX_ITERATIONS = 100
INITIALIZE_CLUSTERS = ['k-means++', 'random']
CONVERGENCE_TOLERANCE = 0.001
NUM_THREADS = 8
----------------------------------------------------------------------------------
if __name__ == '__main__':
k_means(DATASET1, NUM_CLUSTERS, MAX_ITERATIONS, INITIALIZE_CLUSTERS[0],
CONVERGENCE_TOLERANCE, NUM_THREADS)
Dentro del método k_means() empezamos leyendo los datos (puntos) del data set
del que le indicamos, metiendo esos puntos en una lista de numpy arrays:
Llamamos al método fit(x) al que le pasamos la lista de puntos (numpy array), para
que calcule los centroides de los Clusters, el Cluster al que pertenece cada punto y la inercia:
kmeans.fit(points)
El valor de los centroides y el Cluster al que pertenece cada punto lo tenemos en los
atributos cluster_centers_ y labels_ respectivamente, siendo el atributo cluster_centers_
un numpy array de numpy arrays y labels_ una lista de enteros que indica el número del
Cluster al que pertenece cada punto del date set:
centroids = kmeans.cluster_centers_
num_cluster_points = kmeans.labels_.tolist()
Por último implementamos dos métodos para imprimir por pantalla los resultados
obtenidos (centroides, y número de puntos de cada Cluster) y para pintar (con la librería
matplotlib), los centroides y los puntos asignados a cada Cluster:
print_results(centroids, num_cluster_points)
plot_results(centroids, num_cluster_points, points)
Aplicando este script para los 4 data sets propuestos, tenemos los siguientes
resultados:
FINAL RESULT:
Cluster 1
Number Points in Cluster 550
Centroid: [ 2.02972431 2.00259794]
Cluster 2
Number Points in Cluster 196
Centroid: [ 1.01103133 6.88164171]
Cluster 3
Number Points in Cluster 253
Centroid: [ 4.88816341 4.86472536]
Ilustración 27: Resultado final para el Data Set 1 con 999 puntos y 3 Clusters (scikit-learn)
FINAL RESULT:
Cluster 1
Number Points in Cluster 191
Centroid: [ 2.02022231 4.00032196]
Cluster 2
Number Points in Cluster 575
Centroid: [ 2.04429024 1.99783017]
Cluster 3
Number Points in Cluster 233
Centroid: [ 5.15350073 3.09247426]
FINAL RESULT:
Cluster 1
Number Points in Cluster 1977
Centroid: [ 3.96715056 5.01607862]
Cluster 2
Number Points in Cluster 1999
Centroid: [ 0.00084638 0.0212526 ]
Cluster 3
Number Points in Cluster 2003
Centroid: [ 7.01565609 5.00501468]
Cluster 4
Number Points in Cluster 2009
Centroid: [ 5.03315337 2.01020813]
Cluster 5
Number Points in Cluster 2012
Centroid: [ 2.01509102 2.96339142]
Ilustración 29: Resultado final para el Data Set 3 con 10000 puntos y 5 Clusters (scikit-learn)
34 MACHINE LEARNING (en Python), con ejemplos
•! Data Set 4: 7 Clusters y 100000 puntos:
FINAL RESULT:
Cluster 1
Number Points in Cluster 14235
Centroid: [ 3.99180237 5.01440659]
Cluster 2
Number Points in Cluster 14338
Centroid: [ 2.0156146 2.99755542]
Cluster 3
Number Points in Cluster 14356
Centroid: [ -5.19034931e-03 5.99360853e+00]
Cluster 4
Number Points in Cluster 14285
Centroid: [ 0.00899975 -0.01445316]
Cluster 5
Number Points in Cluster 14273
Centroid: [ 5.01486554 1.99725272]
Cluster 6
Number Points in Cluster 14227
Centroid: [-1.00989699 2.99240803]
Cluster 7
Number Points in Cluster 14286
Centroid: [ 7.00982285 5.00231668]
Ilustración 30: Resultado final para el Data Set 3 con 100000 puntos y 7 Clusters (scikit-learn)
Expectation-maximization (EM)
En este ejemplo conocemos los parámetros de las distribuciones normales (la media
y desviación típica) y por tanto; dado un punto cualquiera, vamos a saber a que Cluster
pertenece o a que distribución de probabilidad pertenece (o tiene más probabilidades de
pertenecer).
Por otro lado; para cada una de las distribuciones de probabilidad, tenemos que
calcular sus parámetros; y en este caso asumiendo que se siguen distribuciones normales,
debemos de calcular la media y la desviación típica de cada una de ellas en función de los
objetos de data set. Una vez vayamos ajustando estos valores; según se va ejecutando el
algoritmo del EM, cada uno de los objetos del data set tendrá una probabilidad determinada
de pertenecer a cada unos de los Clusters; por tanto (y de forma similar al K-means con
las distancias), cada objeto pertenecerá a aquel Cluster cuya probabilidad sea mayor (el
producto de πi · pi(x|µi,σi)).
Ilustración 32: Representación gráfica (en Plate Notation) del EM, para una distribución normal (gaussiana)
^ !, A _, I, ` = 0^ ! A, I, ` · 0^ A _
^ ! A, I, `
a a
^ ! _, I, ` = 0 ^ !, 6 = ] _, I, ` = 0 _X · ^X ! , I, ` 0
XKY XKY
a
1 Y Ubcd f
b
^ ! _, I, ` = 0 _X · ·; 4 ed
XKY
`X 2_
Y
Podemos simplificar esta probabilidad ya que es una constante, quedando:
4g
a Y Ubcd f
b
; 4 ed
^ ! _, I, ` = 0 _X ·
`X
XKY
a Y Ubcd f
b
; 4 ed
B9hiB/0 _X ·
`X
XKY
B9hiB/0 _X · ^X ! , I, `
XKY
j?k;D7C0;<0;80A8>CD;9
_X = 0
l7DB80j?k;D7C
\ \
1 1
IX = 0 · 0 /G 000000000020000000000`X = · (/G − 0IX )4
< <−1
GKY \KY
K = num_clusters
for i in range(dataset):
t usvw f
s
r f xw
Cp ∶= argmax00_X
yw
for j in range(K):
|}{r~Ä0rÅ0rÇ0ÉÇÑÄ~rÖ
π{ : = 0
Ü~áÇ0|}{r~Ä
Y â
à{ : = 0 äKY x ä
â
Y Å
σ{ : = · ÅKY(x ä − 0à{ )4
ÅbY
https://github.com/RicardoMoya/ExpectationMaximization_Python
El código que se encuentra en este repositorio hace uso de las librerías de numpy,
matplotlib, scipy y scikit-learn. Para descargar e instalar (o actualizar a la última versión
con la opción -U) estas librerías; con el sistema de gestión de paquetes pip, se deben
ejecutar los siguiente comandos:
Para implementar el EM, vamos a tener objetos que serán representados como
puntos en 2D, por tanto implementaremos una clase Punto (Point.py) para representar los
objetos. Por otro lado se implementa una clase Cluster (Cluster.py) para representar a los
Clusters y que estará compuesta por un conjunto de objetos de la clase Punto. Por último
tendremos un script (EM.py) en el que estará implementado del EM para distribuciones
normales con sus dos pasos de esperanza y maximización para ‘k’ Clusters. A continuación
se muestra a un alto nivel de abstracción el diagrama de clases de la implementación
propuesta del EM:
Los data sets a utilizar en este ejemplo (que se encuentran dentro de la carpeta
dataSet) van a ser ficheros de texto en los que en cada línea van a estar las coordenadas
de cada punto {x,y} separados por el separador “::”. A continuación mostramos un ejemplo
de estos ficheros:
1.857611652::2.114033851
2.34822574::1.58264984
1.998326848::4.118143019
1.714362835::2.468639613
1.656134484::1.909955747
Para los ejemplos disponemos de 4 data sets con las siguientes características:
Nº Clusters Centroides
Nombre Nº Puntos
teóricos teóricos
{2,2}
Visto el diagrama de clases y la estructura de los date sets a utilizar, vamos a pasar
a mostrar la implementación de la clases Punto (Point.py). A esta clase se le va a pasar en
el constructor un “numpy array” con las coordenadas del punto y va a tener como atributos
esa coordenada y las dimensiones de la misma, que para el ejemplo que vamos a mostrar
será de 2:
class Point:
def __repr__(self):
return 'Coordinates: ' + str(self.coordinates) + \
'\n\t -> Dimension: ' + str(self.dimension)
Por otro lado vamos a tener la clase Cluster (Cluster.py) que se le va a pasar en el
constructor una lista de puntos que van a ser los que formen el Cluster y el número de
import numpy as np
class Cluster:
# Check that all elements of the cluster have the same dimension
for p in points:
if p.dimension != self.dimension:
raise Exception(
"Point %s has dimension %d different with %d from the rest "
"of points") % (p, len(p), self.dimension)
old_mean = self.mean
self.points = points
points_coordinates = [p.coordinates for p in self.points]
self.mean = np.mean(points_coordinates, axis=0)
self.std = np.std(points_coordinates, axis=0, ddof=1)
self.cluster_probability = len(points) / float(total_points)
self.converge = np.array_equal(old_mean, self.mean)
import random
import math
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from Point import Point
from Cluster import Cluster
DATASET1 = "./dataSet/DS_3Clusters_999Points.txt"
DATASET2 = "./dataSet/DS2_3Clusters_999Points.txt"
DATASET3 = "./dataSet/DS_5Clusters_10000Points.txt"
DATASET4 = "./dataSet/DS_7Clusters_100000Points.txt"
NUM_CLUSTERS = 3
ITERATIONS = 1000
COLORS = ['red', 'blue', 'green', 'yellow', 'gray', 'pink', 'violet', 'brown',
'cyan', 'magenta']
def dataset_to_list_points(dir_dataset):
"""
Read a txt file with a set of points and return a list of objects Point
:param dir_dataset: path file
"""
points = list()
with open(dir_dataset, 'rt') as reader:
for point in reader:
points.append(Point(np.asarray(map(float, point.split("::")))))
return points
return np.argmax(expectation)
def print_results(clusters):
print '\n\nFINAL RESULT:'
for i, c in enumerate(clusters):
print '\tCluster %d' % (i + 1)
print '\t\tNumber Points in Cluster: %d' % len(c.points)
print '\t\tProbability: %s' % str(c.cluster_probability)
print '\t\tMean: %s' % str(c.mean)
print '\t\tStandard Desviation: %s' % str(c.std)
# Matrix Covariance
cov = np.cov(points, rowvar=False)
# Ellipse Object
ellipse = Ellipse(xy=center, width=width, height=height, angle=angle,
alpha=alpha, color=color)
ax = plt.gca()
ax.add_artist(ellipse)
return ellipse
def plot_results(clusters):
plt.plot()
for i, c in enumerate(clusters):
# plot points
Ricardo Moya García 45
x, y = zip(*[p.coordinates for p in c.points])
plt.plot(x, y, linestyle='None', color=COLORS[i], marker='.')
# plot centroids
plt.plot(c.mean[0], c.mean[1], 'o', color=COLORS[i],
markeredgecolor='k', markersize=10)
# plot area
plot_ellipse(c.mean, [p.coordinates for p in c.points], 0.2, COLORS[i])
plt.show()
converge = False
it_counter = 0
while (not converge) and (it_counter < iterations):
# Expectation Step
for p in points:
i_cluster = get_expecation_cluster(clusters, p)
new_points_cluster[i_cluster].append(p)
# Maximization Step
for i, c in enumerate(clusters):
c.update_cluster(new_points_cluster[i], len(points))
if __name__ == '__main__':
expectation_maximization(DATASET1, NUM_CLUSTERS, ITERATIONS)
if __name__ == '__main__':
expectation_maximization(DATASET1, NUM_CLUSTERS, ITERATIONS)
points = dataset_to_list_points(dataset)
converge = False
it_counter = 0
while (not converge) and (it_counter < iterations):
# Esperanza
for p in points:
i_cluster = get_expecation_cluster(clusters, p)
new_points_cluster[i_cluster].append(p)
# Maximización
for i, c in enumerate(clusters):
c.update_cluster(new_points_cluster[i], len(points))
# ¿CONVERGE?
Ricardo Moya García 47
converge = [c.converge for c in clusters].count(False) == 0
# Incrementamos el contador
it_counter += 1
new_points_cluster = [[] for i in range(num_clusters)]
print_clusters_status(it_counter, clusters)
print_results(clusters)
plot_results(clusters)
NOTA: La implementación de los pasos de Esperanza y Maximización pueden ser optimizados paralelizando los cálculos con
threads (hilos). Por razones didácticas y por legibilidad y claridad del código no se ha optimizado esta parte.
1.! Elección de 3 puntos al azar para inicializar las medias de las distribuciones normales.
Por otro las inicializamos la desviación típica a ‘1’ y la probabilidad de pertenencia a
un Cluster como 1/3:
3.! Iteración 2:
4.! Iteración 3:
6.! Iteración 5:
FINAL RESULT:
Cluster 1
Number Points in Cluster: 195
Probability: 0.195195195195
Mean: [ 0.99752164 6.87917477]
Standard Desviation: [ 0.85525541 0.90396413]
Cluster 2
Number Points in Cluster: 248
Probability: 0.248248248248
Mean: [ 4.90529473 4.91753593]
Standard Desviation: [ 0.79991193 0.94110496]
Cluster 3
Number Points in Cluster: 556
Probability: 0.556556556557
Mean: [ 2.05069432 2.01442116]
Standard Desviation: [ 0.92130407 0.85040552]
Ilustración 34: Resultado final del EM para el Data Set 1 con 999 puntos y 3 Clusters
Ilustración 36: Resultado final del EM para el Data Set 3 con 10000 puntos y 5 Clusters
Ilustración 37: Resultado final del EM para el Data Set 4 con 100000 puntos y 7 Clusters
De forma opcional podemos definir una serie de parámetros con los valores que
consideremos, siendo los más prácticos (según la opinión del autor) los siguientes:
1.! tol: Con este valor indicamos el umbral, tolerancia o margen de error para la
convergencia.
2.! params: Le indicamos los parámetros que debe de actualizar en el paso de
maximización.
Ricardo Moya García 51
Una vez construido el objeto de la clase GMM, debemos de llamar a los métodos
pertinentes para que nos calcule los parámetros anteriormente indicados. En este caso y
para el ejemplo que a continuación mostramos, vamos a llamar el método fit(x) al que
pasamos como parámetro una lista de puntos (cada punto en un numpy array) y nos
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from sklearn.mixture import GMM
# Constant
DATASET1 = "./dataSet/DS_3Clusters_999Points.txt"
DATASET2 = "./dataSet/DS2_3Clusters_999Points.txt"
DATASET3 = "./dataSet/DS_5Clusters_10000Points.txt"
DATASET4 = "./dataSet/DS_7Clusters_100000Points.txt"
NUM_CLUSTERS = 3
MAX_ITERATIONS = 10
CONVERGENCE_TOLERANCE = 0.001
COLORS = ['red', 'blue', 'green', 'yellow', 'gray', 'pink', 'violet', 'brown',
'cyan', 'magenta']
def dataset_to_list_points(dir_dataset):
"""
Read a txt file with a set of points and return a list of objects Point
:param dir_dataset:
"""
points = list()
with open(dir_dataset, 'rt') as reader:
for point in reader:
points.append(np.asarray(map(float, point.split("::"))))
return points
# Ellipse Object
ellipse = Ellipse(xy=center, width=width, height=height, angle=angle,
alpha=alpha, color=color)
ax = plt.gca()
ax.add_artist(ellipse)
return ellipse
# Plot Ellipse
plot_ellipse(mean, covars_matrix_clusters[nc], 0.2, COLORS[nc])
plt.show()
# Object GMM
gmm = GMM(n_components=num_clusters, covariance_type='full', tol=tolerance,
n_init=max_iterations, params='wmc')
means_clusters = gmm.means_
probability_clusters = gmm.weights_
covars_matrix_clusters = gmm.covars_
if __name__ == '__main__':
expectation_maximization(DATASET1, NUM_CLUSTERS, CONVERGENCE_TOLERANCE,
MAX_ITERATIONS)
# Constant
DATASET1 = "./dataSet/DS_3Clusters_999Points.txt"
DATASET2 = "./dataSet/DS2_3Clusters_999Points.txt"
DATASET3 = "./dataSet/DS_5Clusters_10000Points.txt"
DATASET4 = "./dataSet/DS_7Clusters_100000Points.txt"
NUM_CLUSTERS = 3
MAX_ITERATIONS = 10
CONVERGENCE_TOLERANCE = 0.001
COLORS = ['red', 'blue', 'green', 'yellow', 'gray', 'pink', 'violet', 'brown',
'cyan', 'magenta']
----------------------------------------------------------------------------------
if __name__ == '__main__':
expectation_maximization(DATASET1, NUM_CLUSTERS, CONVERGENCE_TOLERANCE,
MAX_ITERATIONS)
means_clusters = gmm.means_
probability_clusters = gmm.weights_
covars_matrix_clusters = gmm.covars_
Por último implementamos dos métodos para imprimir por pantalla los resultados
obtenidos (punto medio, número de puntos de cada Cluster y la probabilidad de
pertenencia) y para pintar (con la librería matplotlib), los puntos medios y los puntos
asignados a cada Cluster:
Aplicando este script para los 4 data sets propuestos, tenemos los siguientes
resultados:
FINAL RESULT:
Cluster 1
Number Points in Cluster 552
Centroid: [ 2.03233538 2.00853155]
Probability: 55.061812%
Cluster 2
Number Points in Cluster 253
Centroid: [ 4.85698668 4.87166594]
Probability: 25.632025%
Cluster 3
Number Points in Cluster 194
Centroid: [ 0.98302746 6.88925282]
Probability: 19.306162%
Ilustración 38: Resultado final del GMM para el Data Set 1 con 999 puntos y 3 Clusters (scikit-learn)
FINAL RESULT:
Cluster 1
Number Points in Cluster 186
Centroid: [ 1.99735203 4.01744321]
Probability: 18.639301%
Cluster 2
Number Points in Cluster 242
Centroid: [ 5.08393907 3.06038361]
Probability: 24.320184%
Cluster 3
Number Points in Cluster 571
Centroid: [ 2.02688227 2.00363213]
Probability: 57.040515%
FINAL RESULT:
Cluster 1
Number Points in Cluster 1971
Centroid: [ 7.02380409 4.97477739]
Probability: 19.503728%
Cluster 2
Number Points in Cluster 1935
Centroid: [-0.03006596 -0.03848878]
Probability: 18.591360%
Cluster 3
Number Points in Cluster 2074
Centroid: [ 3.5474937 4.55700106]
Probability: 19.963076%
Cluster 4
Number Points in Cluster 2012
Centroid: [ 5.0348546 2.00442168]
Probability: 19.923560%
Cluster 5
Number Points in Cluster 2008
Centroid: [ 2.41381883 3.29885127]
Probability: 22.018275%
FINAL RESULT:
Cluster 1
Number Points in Cluster 14270
Centroid: [ 5.00790293 2.00510173]
Probability: 14.267490%
Cluster 2
Number Points in Cluster 14219
Centroid: [-0.99805653 2.99389472]
Probability: 14.217667%
Cluster 3
Number Points in Cluster 14407
Centroid: [ 6.97099609 4.99667353]
Probability: 14.545643%
Cluster 4
Number Points in Cluster 14090
Centroid: [ 1.99643225 2.98306353]
Probability: 13.934259%
Cluster 5
Number Points in Cluster 14329
Centroid: [ 0.0083095 -0.00197396]
Probability: 14.331673%
Cluster 6
Number Points in Cluster 14366
Centroid: [ -4.37927760e-03 5.98768206e+00]
Probability: 14.355278%
Cluster 7
Number Points in Cluster 14319
Centroid: [ 3.940767 4.97634401]
Probability: 14.347991%
Uno de los problemas que nos encontramos a la hora de aplicar alguno de los métodos
de Clustering (K-means o EM) es la elección del número de Clusters. No existe un criterio
objetivo ni ampliamente válido para la elección de un número óptimo de Clusters; pero
tenemos que tener en cuenta, que una mala elección de los mismos puede dar lugar a
realizar agrupaciones de datos muy heterogéneos (pocos Clusters); o datos, que siendo
muy similares unos a otros los agrupemos en Clusters diferentes (muchos Clusters).
Aunque no exista un criterio objetivo para la selección del número de Clusters, si que
se han implementado diferentes métodos que nos ayudan a elegir un número apropiado de
Clusters para agrupar los datos; como son, el método del codo (elbow method), el criterio
de Calinsky, el Affinity Propagation (AP), el Gap (también con su versión estadística),
Dendrogramas, etc. Dada la complejidad de alguno de estos métodos, vamos a explicar
aquellos que son más sencillos y que nos dan; para la mayoría de los casos, unos resultados
que nos permiten tomar la decisión de cuál será el número optimo de Clusters para el
conjunto de datos. Estos métodos serán el método del codo, los Dendrogramas y el Gap.
https://github.com/RicardoMoya/OptimalNumClusters
Este método utiliza los valores de la inercia obtenidos tras aplicar el K-means a
diferente número de Clusters (desde 1 a N Clusters), siendo la inercia la suma de las
distancias al cuadrado de cada objeto del Cluster a su centroide:
J
4
F<;96@B = /G − 0I
GKL
Una vez obtenidos los valores de la inercia tras aplicar el K-means de 1 a N Clusters,
representamos en una gráfica lineal la inercia respecto del número de Clusters. En esta
gráfica se debería de apreciar un cambio brusco en la evolución de la inercia, teniendo la
línea representada una forma similar a la de un brazo y su codo. El punto en el que se
observa ese cambio brusco en la inercia nos dirá el número óptimo de Clusters a seleccionar
para ese data set; o dicho de otra manera: el punto que representaría al codo del brazo
será el número óptimo de Clusters para ese data set.
El script que se muestra a continuación, calcula los valores de la inercia tras aplicar
el K-means de 1 a 20 Clusters (para uno de los 3 data sets que tenemos) y los pinta en una
gráfica lineal (número de Clusters respecto a la inercia) para poder apreciar “el codo” y por
tanto determinar el número optimo de Clusters para el data set:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
# Constant
DATASET1 = "./dataSet/DS_3Clusters_999Points.txt"
def dataset_to_list_points(dir_dataset):
"""
Read a txt file with a set of points and return a list of objects Point
:param dir_dataset:
"""
points = list()
with open(dir_dataset, 'rt') as reader:
for point in reader:
points.append(np.asarray(map(float, point.split("::"))))
return points
def plot_results(inertials):
x, y = zip(*[inertia for inertia in inertials])
plt.plot(x, y, 'ro-', markersize=8, lw=2)
plt.grid(True)
plt.xlabel('Num Clusters')
plt.ylabel('Inertia')
plt.show()
inertia_clusters = list()
# Calculate Kmeans
kmeans.fit(points)
# Obtain inertia
inertia_clusters.append([i, kmeans.inertia_])
plot_results(inertia_clusters)
if __name__ == '__main__':
select_clusters(DATASET1, LOOPS, MAX_ITERATIONS, INITIALIZE_CLUSTERS,
CONVERGENCE_TOLERANCE, NUM_THREADS)
A continuación se muestran los resultados obtenidos para cada uno de los tres data
sets. El script solo devuelve la gráfica lineal. La representación de los Clusters que se
muestra al lado de la gráfica lineal se ha obtenido con el scripts que implementa el EM y se
muestran para poder apreciar que el número de Clusters que nos indica el método del codo
es coherente:
Ilustración 44: Numero de Clusters vs Inercia. Data Ilustración 45: Resultado del data set 2 para 3
set 2. Clusters.
Ilustración 46: Numero de Clusters vs Inercia. Data Ilustración 47: Resultado del data set 3 para 5
set 3. Clusters.
Como se puede apreciar en los resultados obtenidos, el método del codo devuelve
unos valores muy coherentes y se ajusta a los resultados esperados. Es posible que al
aplicar este método para otro conjunto de datos no se aprecie “el codo” o incluso se
observen dos o más codos (o cambios bruscos en la evolución de la inercia). En ese caso
Dendrogramas
Siguiendo estos pasos, el dendrograma resultante para estudiar la relación entre los
9 puntos antes mostrados sería el siguiente, dando lugar a interpretar que el número optimo
de Clusters a seleccionar serian 3:
El script que se muestra a continuación calcula con el método linkage() las relaciones
entre los puntos y grupos más similares, representando estos resultado en un dendrograma
al cual hemos limitado el nivel de detalle de las agrupaciones hasta que muestre en su nivel
más bajo 12 grupos de objetos:
import numpy as np
import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import dendrogram, linkage
# Constant
DATASET1 = "./dataSet/DS_3Clusters_999Points.txt"
DATASET2 = "./dataSet/DS2_3Clusters_999Points.txt"
DATASET3 = "./dataSet/DS_5Clusters_10000Points.txt"
def dataset_to_list_points(dir_dataset):
"""
Read a txt file with a set of points and return a list of objects Point
:param dir_dataset:
"""
def plot_dendrogram(dataset):
points = dataset_to_list_points(dataset)
plt.title('Dendrogram')
plt.xlabel('Points')
plt.ylabel('Euclidean Distance')
# Generate Dendrogram
dendrogram(
Z,
truncate_mode='lastp',
p=12,
leaf_rotation=90.,
leaf_font_size=12.,
show_contracted=True
)
plt.show()
if __name__ == '__main__':
plot_dendrogram(DATASET1)
A continuación se muestran los resultados obtenidos para cada uno de los tres data
sets. El script solo devuelve el dendrograma. La representación de los Clusters que se
muestra al lado del dendrograma se ha obtenido con el scripts que implementa el EM y se
muestran para poder apreciar que el número de Clusters que nos indica el dendrograma.
Ilustración 50: Dendrograma resultante para el data Ilustración 51: Resultado del data set 1 para 3
set 1. Clusters.
Ilustración 54: Dendrograma resultante para el data Ilustración 55: Resultado del data set 3 para 5
set 3. Clusters.
Como puede observarse en los resultados obtenidos, los dendrogramas muestran las
agrupaciones (Clusters) de objetos esperados. Al igual que en la aplicación del método del
codo, es posible que no se puedan apreciar claramente las agrupaciones de objetos, por lo
que habría que estudiar con otras técnicas el número óptimo de Clusters a seleccionar.
Gap
El último de los métodos que vamos a mostrar es el Gap (brecha); similar al método
del codo, cuya finalidad es la de encontrar la mayor diferencia o distancia que hay entre los
diferentes grupos de objetos que vamos formando para representarlos en un dendrograma.
Para ello vamos cogiendo las distancias que hay de cada uno de los enlaces que forman el
dendrograma y vemos cual es la mayor diferencia que hay entre cada uno de estos enlaces.
import numpy as np
import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import linkage
# Constant
DATASET1 = "./dataSet/DS_3Clusters_999Points.txt"
DATASET2 = "./dataSet/DS2_3Clusters_999Points.txt"
DATASET3 = "./dataSet/DS_5Clusters_10000Points.txt"
def dataset_to_list_points(dir_dataset):
"""
Read a txt file with a set of points and return a list of objects Point
:param dir_dataset:
"""
points = list()
with open(dir_dataset, 'rt') as reader:
for point in reader:
points.append(np.asarray(map(float, point.split("::"))))
return points
def plot_gap(dataset):
points = dataset_to_list_points(dataset)
# Calculate Gap
gap = np.diff(last, n=2) # second derivative
plt.plot(num_clustres[:-2] + 1, gap[::-1], 'ro-', markersize=8, lw=2)
plt.show()
if __name__ == '__main__':
plot_gap(DATASET1)
A continuación se muestran los resultados obtenidos para cada uno de los tres data
sets. El script solo devuelve la gráfica lineal. La representación de los Clusters que se
muestra al lado de la gráfica lineal se ha obtenido con el scripts que implementa el EM y se
muestran para poder apreciar que el número de Clusters que nos indica la gráfica.
Ilustración 58: GAP resultante para el data set 2. Ilustración 59: Resultado del data set 2 para 3
Clusters.
Ilustración 60: GAP resultante para el data set 3. Ilustración 61: Resultado del data set 3 para 5
Clusters.
Expectation7maximization,!35!
A! N!
G!
Aprendizaje!adaptativo,!10! NP7completo,!4!
Aprendizaje!Autónomo,!4! Gap,!66!
Aprendizaje!no!supervisado,!10!
O!
Aprendizaje!on7line,!10!
H!
Overfitting,!7!
Aprendizaje!por!refuerzo,!10! Hipótesis,!6!
Aprendizaje!semi7supervisado,!10! Hold!Out,!11!
P!
Aprendizaje!supervisado,!10!
Partición,!11!
I!
Plate!Notation,!37!
C!
Inercia,!15!
Clasificación,!5,!6! Inteligencia!Artificial,!4!
R!
Cluster,!13!
Regresión,!5,!6!
Clustering,!13! K!
Resustitución,!11!
Cross!Validation,!11!
K7means,!15!
S!
D! L!
Sistema!experto,!5!
Data!set,!4!
Leaving!one!out,!11!
Dendrogramas,!63! U!
M!
Underfitting,!7!
E!
Machine!Learning,!4!
Elbow!Method,!60!
Método!del!codo,!60!
V!
Error!empírico,!6!
Validación!cruzada,!11!
Exclusión!individual,!11!
variables!latentes,!36!