Todos los desafíos
Intermedio 0 resueltos 0% de aceptación

Agrupamiento k-means

Agrupa puntos en k clústeres asignándolos repetidamente al centroide más cercano y moviendo los centroides.

Lo que aprenderás

  • Asignar puntos al centroide más cercano
  • Mover los centroides a la media del grupo
  • Repetir un algoritmo hasta que se estabilice

Problema

Ver original (inglés)

K-means encuentra grupos en datos sin etiquetar. Empezando por los centroides dados, repite iterations veces:

  1. Asignar: coloca cada punto en el clúster de su centroide más cercano (distancia euclidiana). Si dos centroides están igual de cerca, elige el de índice menor.
  2. Actualizar: mueve cada centroide al promedio de los puntos asignados a él. Un centroide sin puntos se queda donde está.

Implementa k_means(points, centroids, iterations).

Entrada

points: Los puntos de datos, cada uno una lista de coordenadas.

centroids: Los k centroides iniciales, con el mismo número de coordenadas.

iterations: Cuántas rondas de asignar y actualizar ejecutar.

Salida

Devuelve los centroides finales en su orden original.

Restricciones

1 ≤ número de puntos ≤ 1000, 1 ≤ k ≤ 20, 1 ≤ dimensiones ≤ 10

0 ≤ iterations ≤ 100

-1000 ≤ cada coordenada ≤ 1000

Ejemplos

Ejemplo 1
Entrada:
points = [
    [1.0, 1.0],
    [1.5, 2.0],
    [8.0, 8.0],
    [9.0, 8.5]
]
centroids = [
    [0.0, 0.0],
    [10.0, 10.0]
]
iterations = 1

Salida esperada:
expected = [
    [1.25, 1.5],
    [8.5, 8.25]
]
Entrada:
std::vector<std::vector<double>> points = {
    {1.0, 1.0},
    {1.5, 2.0},
    {8.0, 8.0},
    {9.0, 8.5}
};
std::vector<std::vector<double>> centroids = {
    {0.0, 0.0},
    {10.0, 10.0}
};
long long iterations = 1;

Salida esperada:
std::vector<std::vector<double>> expected = {
    {1.25, 1.5},
    {8.5, 8.25}
};
Entrada:
double[][] points = new double[][] {
    new double[] {1.0, 1.0},
    new double[] {1.5, 2.0},
    new double[] {8.0, 8.0},
    new double[] {9.0, 8.5}
};
double[][] centroids = new double[][] {
    new double[] {0.0, 0.0},
    new double[] {10.0, 10.0}
};
long iterations = 1;

Salida esperada:
double[][] expected = new double[][] {
    new double[] {1.25, 1.5},
    new double[] {8.5, 8.25}
};

Explicación

Los dos primeros puntos están más cerca de (0, 0) y los dos últimos de (10, 10). Los nuevos centroides son los promedios: ((1 + 1.5) / 2, (1 + 2) / 2) = (1.25, 1.5) y ((8 + 9) / 2, (8 + 8.5) / 2) = (8.5, 8.25).

Ejemplo 2
Entrada:
points = [
    [0.0],
    [1.0],
    [10.0]
]
centroids = [
    [0.0],
    [100.0]
]
iterations = 2

Salida esperada:
expected = [
    [3.666667],
    [100.0]
]
Entrada:
std::vector<std::vector<double>> points = {
    {0.0},
    {1.0},
    {10.0}
};
std::vector<std::vector<double>> centroids = {
    {0.0},
    {100.0}
};
long long iterations = 2;

Salida esperada:
std::vector<std::vector<double>> expected = {
    {3.666667},
    {100.0}
};
Entrada:
double[][] points = new double[][] {
    new double[] {0.0},
    new double[] {1.0},
    new double[] {10.0}
};
double[][] centroids = new double[][] {
    new double[] {0.0},
    new double[] {100.0}
};
long iterations = 2;

Salida esperada:
double[][] expected = new double[][] {
    new double[] {3.666667},
    new double[] {100.0}
};

Explicación

Ronda 1: (100) está lejos de todos los puntos, así que los tres puntos van al centroide 1, que se mueve a (0 + 1 + 10) / 3 ≈ 3.666667; el centroide 2 no recibe puntos y se queda en 100. La ronda 2 asigna igual, así que el resultado es [[3.666667], [100]].

Referencias

Este reto está adaptado para CodeUtility. Sigue el enunciado y las restricciones indicadas arriba.

Aprende de otros

Soluciones de la comunidad

Aún no hay soluciones publicadas. Resuelve este reto para compartir la primera.