No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

K-Means en Python

27/28
Recursos

Aportes 26

Preguntas 5

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

No creo poder hacer este código yo solo en este momento 😦
Alguien más ?

Esta es la forma en la que use el array A[1] para poder diferenciar los grupos que se forman:

# Guardo en las listas G_1, G_2 y G_3 la posicion en la que estan los valores 1,2 o 3 de mi array A[1]
G_1 = []
G_2 = []
G_3 = []
for i in range(len(A[1])):
    if A[1][i] == 1:
        G_1.append(i)
    elif A[1][i] == 2:
        G_2.append(i)
    elif A[1][i] == 3:
        G_3.append(i)
        
# Separar los datos para poder graficarlos
X_1 = [X[:,0][G_1[i]] for i in range(len(G_1))]
Y_1 = [X[:,1][G_1[i]] for i in range(len(G_1))]

X_2 = [X[:,0][G_2[i]] for i in range(len(G_2))]
Y_2 = [X[:,1][G_2[i]] for i in range(len(G_2))]

X_3 = [X[:,0][G_3[i]] for i in range(len(G_3))]
Y_3 = [X[:,1][G_3[i]] for i in range(len(G_3))]

Para graficarlo:

fig,ax = plt.subplots(1,1,figsize=(7,7),dpi=100)

ax.scatter( X_1, Y_1, color='red', label='Grupo 1')
ax.scatter( X_2, Y_2, color='blue', label='Grupo 2')
ax.scatter( X_3, Y_3, color='black', label='Grupo 3')
ax.set_xlim(-1.5,2.5)
ax.set_ylim(-2,2)
plt.legend()
plt.show()

![](

import pandas as pd
import matplotlib.pyplot as plt

clusters = list(zip(X,A[1]))

df = pd.DataFrame(clusters,columns=["Vectores","k"])
k = df.groupby("k")
k1 = k.get_group(1).iloc[:,0]
k2 = k.get_group(2).iloc[:,0]
k3 = k.get_group(3).iloc[:,0]

grupo1 = np.array([k1]).astype(float).reshape(101,2)
grupo2 = np.array([k2]).astype(float).reshape(99,2)
grupo3 = np.array([k3]).astype(float).reshape(100,2)

fig,ax = plt.subplots(1,1,figsize=(7,7),dpi=120)
ax.scatter( grupo1[:,0],grupo1[:,1], color='red',label='Grupo1')
ax.scatter( grupo2[:,0],grupo2[:,1], color="green", label = 'Grupo2')
ax.scatter( grupo3[:,0],grupo3[:,1], color="black", label = ' Grupo3')
ax.set_xlim(-1.5,2.5)
ax.set_ylim(-2,2)
plt.legend()
plt.show()

A mi al correr de nuevo el algoritmo me dio esta distribucion de puntos:

![](

Aqui la solución para el dataset fetch_openml
Me base en el código del google colab, solo le cambie me pequeñas cosas.

Me tardó bastante en procesar, y pense que no me cargaría, asi que lo deje un largo tiempo, despues de 30 iteracioes este es mi resultado.

from sklearn.datasets import fetch_openml
import random

X, y = fetch_openml('mnist_784', version=1, return_X_y=True)
import itertools
a = list(itertools.product(range(3),range(3)))
X_array = np.array(X)
X_array.shape
A = Kmeans_alg(X_array,random.choices(X_array,k=9))
fig, ax = plt.subplots(3,3,figsize=(7,7),dpi=120)
for i,j in zip(a,A[0]):
        ax[i[0]][i[1]].imshow(j.reshape(28,28))
plt.show()

Para gráficar los grupos, les recomiendo usar pandas y la librería seaborns.

import pandas as pd 
import seaborn as sns

gruping = A[1].reshape(-1,1)
arr = np.concatenate((X, gruping),axis=1)

df = pd.DataFrame(arr,columns=['x', 'y', 'group'])

fig,ax= plt.subplots(1,1,figsize=(7,7),dpi=300)
sns.scatterplot(x='x',y='y',hue='group',data=df, palette='deep')
for i in A[0]:
    ax.scatter(i[0],i[1],c='black',linewidths=3)
plt.show()

La verdad no se si dejarlo como aporte o como pregunta porque no se el fetch_openml me regreso un DataFrame en lugar de un arreglo de Numpy, además yo pensaba que así como trabajaba con Numpy lo podía hacer con Pandas pero no me dejo. Tuve que revisar el tipo de dato que me regresaba para darme cuenta de eso, para poder cambiar de Pandas a Numpy lo que hice fue:

X = np.array(X)

La verdad es algo simple pero me tarde bastante para darme cuenta jajajaja. Aun así pude obtener los resultados aunque tardo más de 7 minutos en obtener los centroides.

En el caso de los colores fue sencillo porque lo primero que hice fue hacer un arreglo booleano para cada grupo de la siguiente manera:

red = A[1]==1
blue = A[1]==2
green = A[1]==3

Después utilizando esos arreglos hice tres arreglos diferentes para definir cada cluster de la siguiente manera:

X_red=Y[red]
X_blue=Y[blue]
X_green=Y[green]

Y finalmente realicé la gráfica. Dejo mi archivo que realicé en Deepnote para el proyecto final. Me encantaría recibir sus sugerencias.

Mi codigo de grafica:

  1. Creo una lista con la cantidad de grupos
  2. Pregunto cual esta en cada lista y la agrego a un sub-indice de gropus
groups = [ [] for i in range(len(A[0]))]
for i in range(len(groups)):
  for j in range(len(A[1])):
    if A[1][j] == i+1:
      groups[i].append(j)
  1. Creo 2 listas grandes, allx y ally que van a contener a todos los X y Y de cada sub-lista
allx = []
for j in range(len(groups)):
  val = [X[:,0][groups[j][i]] for i in range(len(groups[j]))]
  allx.append(val)

ally = [ ]
for j in range(len(groups)):
  val = [X[:,1][groups[j][i]] for i in range(len(groups[j]))]
  ally.append(val)
  1. Grafico, iterando igualmente con len(groups)
fig,ax = plt.subplots(1,1,figsize=(7,7),dpi=100)
for i in range(len(groups)):
    ax.scatter(allx[i], ally[i])
plt.show()

Todo esta mas claro en mi notebook ♥

Bueno el ultimo reto demora en procesar sera motivo para investigar la librería fetchopenml

import numpy as np 
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_openml
import itertools
import random

def group_assignment(data, centroids):
    grouping_vec_c = np.zeros((len(data)))
    for i in range(len(data)): # recorrido de toda la data
        dist = np.zeros(len(centroids))
        for j in range(len(centroids)): # recorrido de centroides en este caso son 3 para obtener la distancia con cada centroide
            dist[j] = np.linalg.norm(data[i] - centroids[j]) # vector dist contiene las distancias de cada vector de data con cada centroide.
        min_dist = min(dist)        # min_dist contiene la distancia minima del versos data - centroides
        for j in range(len(centroids)): # con este for encontramos el indice de la distancia minima ubicada en ese vector con el dato actual
            if min_dist == dist[j]:
                grouping_vec_c[i] = j + 1 # al vector grouping_vec_c que esta vinculado al vector data  se le asigna un grupo segun cercania a los centriodes 1, 2, y 3
    return grouping_vec_c


def update_centroid(data, grouping, centroids):
    new_centroids = []
    for i in range(len(centroids)): # bucle para recorrer los centroides
        cent = np.zeros(len(data[0])) # porque nbo hacer un np.zeros(1)
        count = 0
        for j in range(len(data)): # bucle para para recorrer la daa
            if grouping[j] == i + 1:    # compara si el vector de grupos grouping_vec_c asociado a lo vector data comparado con su grupo.
                cent = cent + data[j]
                count += 1
        group_average =  cent/count # vector promedio de cada grupo asociado a cada centroide
        new_centroids.append(group_average) # nuevo vector de centroides es el promedio de cada grupo de centroides
    return new_centroids

def clustering_objetive(data, grouping, centroids):
    J_obj = 0
    for i in range (len(data)):     # recorre data
        for j in range(len(centroids)): # recorre centroides
            if grouping[i] == j + 1:    # compara cada grupo de data asignado al vector grouping_vec_c
                J_obj += np.linalg.norm(data[i] - centroids[j])**2 # obtiene la suma de las distancias entre el vetor centroide y su grupo de datos asignados
    J_obj = J_obj/len(data) #promedio de la suma de distancias vinculadas a a todos los centroides
    return J_obj    # promedio de distancias


def Kmeans_alg(data, centroids):
    iteration = 0
    J_obj_vector = []
    Stop = False
    while Stop == False:
        grouping = group_assignment(data, centroids) # ingresamos data y centroides para obtener el vector grouping vinculando el vector data a cada grupo
        new_centroids = update_centroid(data, grouping, centroids) # Ingresamos datam grouping y centroids para obtener el nuevo vector de centroides
        J_obj = clustering_objetive(data, grouping, new_centroids)  # Ingresamos data, grouping y new_centroids para obtener el promedio de distancias dato de grupo vs centroide de grupo
        J_obj_vector.append(J_obj) # Vector J_Obj almacena el promedio de distancias por grupo-centroide
        iteration +=1
        if np.linalg.norm(np.array(new_centroids) - np.array(centroids)) < 1e-6: #compara la distancia entre centroides viejos vs los nuevos centroides para ver si se mueven poco
            Stop = True
        else:
            centroids = new_centroids   
    return new_centroids, grouping, J_obj_vector, iteration

if __name__ == '__main__':

    fig,ax = plt.subplots(1,1,figsize=(7,7),dpi=120)
    X = np.concatenate([[0.3*np.random.randn(2) for i in range(100)],\
                        [[1,1] + 0.3*np.random.randn(2) for i in range(100)], \
                        [[1,-1]+ 0.3* np.random.randn(2) for i in range(100)]])
    ax.scatter( X[:,0],X[:,1])
    ax.set_xlim(-1.5,2.5)
    ax.set_ylim(-2,2)
    #plt.show()

    A = Kmeans_alg(X, X[:3])
    fig, ax = plt.subplots(1, 1, figsize=(7,7),dpi=120)
    plt.plot(list(range(A[-1])), A[2])
    #plt.show()

    grouping = A[1]
    
    v_grupo1 = []
    v_grupo2 = []
    v_grupo3 = []

    fig, ax = plt.subplots(1, 1, figsize=(7,7), dpi=100)
    for i, d_val in enumerate(X):
        if grouping[i] == 1:
            v_grupo1.append(d_val)
        elif grouping[i] == 2:
            v_grupo2.append(d_val)
        elif grouping[i] == 3:
            v_grupo3.append(d_val)

    x1, y1 = zip(*v_grupo1)
    x2, y2 = zip(*v_grupo2)
    x3, y3 = zip(*v_grupo3)
    
    ax.scatter(x1, y1, color='red', label='Grupo 1')     
    ax.scatter(x2, y2, color='blue', label='Grupo 2') 
    ax.scatter(x3, y3, color='green', label='Grupo 3')  

    ax.set_xlim(-1.5,2.5)
    ax.set_ylim(-2,2)
    plt.legend()
    plt.show()

    # B, y = fetch_openml('mnist_784', version=1, return_X_y=True)
    
    # A = Kmeans_alg(B, random.choices(B,k=9))
    # a = list(itertools.product(list(range(3)),list(range(3))))
    # fig, ax = plt.subplots(3,3,figsize=(7,7),dpi=120)
    # for i,j in zip(a,A[0]):
    #         ax[i[0]][i[1]].imshow(j.reshape(28,28))

    # plt.show()

Creamos una lista de colores

ListColor = []
for i in range(len(A[1])):
  if A[1][i]==1.0:
    ListColor.append('red')
  if A[1][i]==2.0:
    ListColor.append('green')
  if A[1][i]==3.0:
    ListColor.append('blue')

Y luego lo agregamos cuando imprimamos los elementos

fig,ax = plt.subplots(1,1,figsize=(7,7),dpi=120)
ax.scatter( X[:,0],X[:,1],color=ListColor)
ax.set_xlim(-1.5,2.5)
ax.set_ylim(-2,2)
plt.show()
Hola! Les comparto el código usado para colocar los grupos al array X generado. ```python X2 = np.insert(X, X.shape[1],A[1], axis=1) fig,ax = plt.subplots(1,1,figsize=(7,7),dpi=120) ax.margins(0.05) for i in range(1,4): X3 = X2[X2[:,2] == i] ax.plot(X3[:,0],X3[:,1], marker='.', linestyle='', ms=12, label=i) ax.legend() plt.show() ax.set_xlim(-1.5,2.5) ax.set_ylim(-2,2) plt.show() ```y su resultado: ![](https://static.platzi.com/media/user_upload/Sin%20t%C3%ADtulo-33d44064-1bc0-4b9c-8a2e-81135d159c7b.jpg)
import numpy as np
import matplotlib.pyplot as plt

def Kmeans_alg(data, centroids):
    iteration = 0
    J_obj_vector = []
    Stop = False
    while Stop == False:
        grouping = group_assignment(data, centroids)
        new_centroids = update_centroid(data, grouping, centroids)
        J_obj = clustering_objective(data, grouping, new_centroids)
        J_obj_vector.append(J_obj)
        iteration += 1
        if np.linalg.norm(np.array(new_centroids) - np.array(centroids)) < 1e-6:
            Stop = True
        else:
            centroids = new_centroids
    return new_centroids, grouping, J_obj_vector, iteration

def group_assignment(data, centroids):
    # Implementación de asignación de grupos
    pass

def update_centroid(data, grouping, centroids):
    # Implementación de actualización de centroides
    pass

def clustering_objective(data, grouping, centroids):
    J_obj = 0
    for i in range(len(data)):
        for j in range(len(centroids)):
            if grouping[i] == (j+1):
                J_obj += np.linalg.norm(data[i] - centroids[j])**2
    J_obj = J_obj/len(data)
    return J_obj

# Generar datos de muestra
X = np.concatenate([[0.3*np.random.randn(2) for i in range(100)],\
                    [[1,1] + 0.3*np.random.randn(2) for i in range(100)], \
                    [[1,-1]+ 0.3* np.random.randn(2) for i in range(100)]])

# Llamar a la función Kmeans_alg
centroids, _, _, _ = Kmeans_alg(X, X[:3])

# Graficar los puntos y los centroides
plt.scatter(X[:, 0], X[:, 1], label='Puntos')
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', marker='X', label='Centroides')
plt.legend()
plt.xlabel('Eje X')
plt.ylabel('Eje Y')
plt.title('Clustering con K-means')
plt.show()

print("Centroides:")
print(centroids)

Antes de ver, les comparto una implementación que hice en el curso de pensamiento probabilístico:

github.com/Erik-Lopez/kmeans-implementation

Hola, en la versión actual de pandas existe un problema con el método reshape, por lo que debemos utilizar el método .values.reshape para poder ingresar los valores a nuestro algoritmo. También hay que utilizar la búsqueda por índice con .iloc

A continuación los cambios para poder utilizar los algoritmos

import random
X_reshape = [ X.iloc[i].values.reshape(28,28) for i in range(len(X))]
C = kmeans(X_reshape,random.choices(X_reshape,k=10))

Luego los resultados fueron

https://circuitdigest.com/microcontroller-projects/raspberry-pi-based-emotion-recognition-using-opencv-tensorflow-and-keras

El reconocimiento de imagenes lo uso con la raspberry Pi, muy facil de implementar el projecto, con tensorflow y keras

RETO 1

G1 = np.array([X[i] for i in range(len(X)) if A[1][i] == 1])
G2 = np.array([X[i] for i in range(len(X)) if A[1][i] == 2])
G3 = np.array([X[i] for i in range(len(X)) if A[1][i] == 3])

fig,ax = plt.subplots(1,1,figsize=(7,7),dpi=120)
ax.scatter( G1[:,0], G1[:,1], color="red", label='Grupo 1')
ax.scatter( G2[:,0], G2[:,1], color="blue", label='Grupo 2')
ax.scatter( G3[:,0], G3[:,1], color="green", label='Grupo 3')
ax.set_xlim(-1.5,2.5)
ax.set_ylim(-2,2)
plt.legend()
plt.show()

RETO 2

Este reto fue muy interesante. Lo primero es que fue necesario hacer esto X=np.array(X) para que el código funcionara con el dataset de los números, ya que X era de tipo dataframe en lugar de un arreglo de numpy. La clusterización se realiza en 10 grupos (lo 10 digitos).

from sklearn.datasets import fetch_openml
import matplotlib.pyplot as plt
import numpy as np
import random
import itertools

X, y = fetch_openml('mnist_784', version=1, return_X_y=True)
X=np.array(X)
A = Kmeans_alg(X,random.choices(X,k=10))
a = list(itertools.product(list(range(3)),list(range(4))))

fig, ax = plt.subplots(3,4,figsize=(7,7),dpi=120)
for i,j in zip(a,A[0]):
        ax[i[0]][i[1]].imshow(j.reshape(28,28))
plt.show()

obteniendo lo siguiente:

esto que vemos es el grupo de vectores representativos, por eso es que se ven algo difusos, ya que fue la mejor adaptación que el algoritmo encontró. Tambien podemos notar que la clusterización no es lo suficientemente buena para este caso, ya que repite números como el 1, además de que le cuesta diferenciar el número 4 y 5. Y bueno, el 7 ni aparece por ahí XD.


Hice otro código para ver si estimaba correctamente los números. Le pedi que me mostrara los primeros números que reconociera como un tres

a partir de esto estimo una eficiencia de aproximadamente 60% para detectar el número tres .

Con el número seis le fue mucho mejor.
El código que usé es el siguiente:

G1 = np.array([X[i] for i in range(len(X)) if A[1][i] == 3])
b = list(itertools.product(list(range(4)),list(range(4))))

fig, ax = plt.subplots(4,4,figsize=(7,7),dpi=120)
for i,j in zip(b,G1):
        ax[i[0]][i[1]].imshow(j.reshape(28,28))
plt.show()

OJO! el vector A[1] (el cual me indica a qué cluster se asignó cada vector) no necesariamente coincide con el número que se busca hallar (parece obvio pero yo tambien tuve la duda).

Reto 1

Hola a todos comparto mi solución al reto propuesto en esta clase. Fue laborioso pero aprendí mucho:

Este es el código con el que agrupe:

position= A[1]
point= X
g_1= []
g_2= []
g_3= []

for indice, valor in enumerate(point):
  if position[indice] == 1:
    g_1.append(valor)
  elif position[indice] == 2:
    g_2.append(valor)
  elif position[indice] == 3:
    g_3.append(valor)

g_1= np.array(g_1)
g_2= np.array(g_2)
g_3= np.array(g_3)

Este fue el código con el que grafique:

fig,ax  = plt.subplots(1,1,figsize=(7,7),dpi=120)
ax.scatter(g_1[:,0],g_1[:,1], linestyle='dashed',label='Grupo 1',color="black")
ax.scatter(g_2[:,0],g_2[:,1], linestyle='dashed',label='Grupo 2',color="orange")
ax.scatter(g_3[:,0],g_3[:,1], linestyle='dashed',label='Grupo 3',color="brown")
ax.set_xlabel('A')
ax.set_ylabel('B')
ax.legend()
ax.set_xlim(-1.5,2.5)
ax.set_ylim(-2,2)
plt.show()

Esta fue la gráfica resultante:

Reto 2 de la clase: Obtención de vectores principales para dibujar del 0 al 9.

Reto de visualización de vectores de acuerdo a los vectores.

Paso 1:Poner los datos en un dataframe

df_cluster=pd.DataFrame([list(X[:,0]),list(X[:,1]),list(A[1])])
df_cluster=df_cluster.T
df_cluster[2]=df_cluster[2].astype('int')
df_cluster[2]=df_cluster[2].astype('str')
df_cluster=df_cluster.rename(columns={0: "V1.1", 1:"V1.2",2: "GR"})
df_cluster.head()

Paso 2: Graficar

fig,ax = plt.subplots(1,1,figsize=(7,7),dpi=120)
colorres = {'1':'red', '2':'green', '3':'blue'}

grouped = df_cluster.groupby('GR')
for key, group in grouped:
    keys=str(key)
    group.plot(ax=ax, kind='scatter', x='V1.1', y='V1.2', label=key, color=colorres[keys])

plt.show()

ax.set_xlim(-1.5,2.5)
ax.set_ylim(-2,2)
ax.legend()
plt.show()

Código para seccionar los cluster por colores

fig,ax = plt.subplots(1,1,figsize=(7,7),dpi=120)

colores = []
for x,a in zip(X,A[1]):
    if a == 1.:
        a = 'red'
    if a == 2.:
        a = 'blue'
    if a == 3.:
        a = 'green'
    colores.append(a)
    
ax.scatter(X[:,0],X[:,1],color=colores)

ax.set_xlim(-1.5,2.5)
ax.set_ylim(-2,2)
plt.show()```

Adjunto mi imagen 😉

mi solución para el grafico de los grupos 🤠

A = Kmeans_alg(X,X[:3])
B=A[1]
g1=[]
g2=[]
g3=[]
for grupo in range(len(B)):
  if B[grupo]==1:
    g1.append([X[grupo,0],X[grupo,1]])
  elif B[grupo]==2:
    g2.append([X[grupo,0],X[grupo,1]])
  elif B[grupo]==3:
    g3.append([X[grupo,0],X[grupo,1]])
g1=np.array(g1)
g2=np.array(g2)
g3=np.array(g3)

fig,ax = plt.subplots(1,1,figsize=(7,7),dpi=100)
ax.scatter(g1[:,0],g1[:,1], color="blue", label='G1')
ax.scatter(g2[:,0],g2[:,1], color="red", label="G2")
ax.scatter(g3[:,0],g3[:,1], color="green", label="G3")
ax.set_xlim(-1.5,2.5)
ax.set_ylim(-2,2)
plt.legend()
plt.show()
colors = A[1]
fig,ax = plt.subplots(1,1,figsize=(7,7),dpi=120)
X = np.concatenate([[0.3*np.random.randn(2) for i in range(100)],\
                    [[1,1] + 0.3*np.random.randn(2) for i in range(100)], \
                    [[1,-1]+ 0.3* np.random.randn(2) for i in range(100)]])
ax.scatter( X[:,0],X[:,1], c= colors, label= colors)
ax.set_xlim(-1.5,2.5)
ax.set_ylim(-2,2)
plt.show()```

Mi codigo para graficar los clusters con colores

color_arr = ('red','blue','green')
fig, ax = plt.subplots(1,1,figsize=(7,7),dpi=120)
cluster_matrix = [[] for i in range(int(np.max(A[1])))]

for i in range(len(X)):
  idx = int(A[1][i]-1)
  cluster_matrix[idx].append(X[i])

for (i,cluster) in enumerate(cluster_matrix):
  cluster = np.asarray(cluster)
  ax.scatter(cluster[:,0],cluster[:,1], c=color_arr[i])
# Grafica los centroides con una x morada
ax.scatter(np.asarray(A[0])[:,0], np.asarray(A[0])[:,1], marker='X', s=70, c = 'purple')

Tengo una duda en la funcion update_centroid()
la siguiente linea de código

cent = np.zeros(len(data[0]))

porque no solo ponerle [0,0] si siempre da lo mismo, o es se utiliza para algo mas?

Así me quedó con colores![](