K-means es un algoritmo de agrupamiento estándar no supervisado que, dado un conjunto de "puntos" y una cantidad de grupos K, asignará cada "punto" a uno de los K grupos.
Pseudocódigo de K-medias
Tenga en cuenta que hay muchas variantes de K-means. Tienes que implementar el algoritmo que describo a continuación. Es posible que tenga alguna variación en el algoritmo o use elementos integrados siempre que obtenga el mismo resultado que este algoritmo con los mismos puntos iniciales.
En este desafío, todas las entradas serán puntos en el plano 2D (cada punto está representado por sus coordenadas en x e y).
Inputs: K, the number of clusters
P, the set of points
Choose K points of P uniformly at random
Each chosen point is the initial centroid of its cluster
Loop:
For each point in P:
Assign to the cluster whose centroid is the nearest (Euclidean distance)
In case of a tie, any of the tied cluster can be chosen
Recompute the centroid of each cluster:
Its x coordinate is the average of all x's of the points in the cluster
Its y coordinate is the average of all y's of the points in the cluster
Until the clusters don't change from one iteration to the next
Output: the set of clusters
Entradas y salidas
- Puede tomar K y P
STDIN
, o como un argumento de función, etc. - P y los puntos en P pueden representarse utilizando cualquier estructura que sea natural para los conjuntos / listas en el idioma que elija.
- K es un entero estrictamente positivo.
- Puede suponer que las entradas son válidas.
- Siempre habrá al menos K puntos en P.
- Puede enviar los clústeres a
STDOUT
, devolverlos desde una función, etc. - El orden de los grupos y el orden dentro de los grupos no es importante. -Puede devolver grupos de puntos para representar grupos, o cada punto etiquetado con un identificador para el grupo (por ejemplo, un número entero).
Casos de prueba
Dado que los grupos resultantes dependen de los puntos elegidos inicialmente, es posible que no todos obtengan los mismos resultados (o el mismo resultado cada vez que ejecute su código).
Por lo tanto, solo tome la salida como salida de ejemplo.
Input:
K = 1
P = [[1,2.5]]
Output:
[[[1,2.5]]]
Input:
K = 3
P = [[4,8], [15,16], [23,42], [-13.37,-12.1], [666,-666]]
Output:
[[[666,-666]],[[-13.37,-12.1],[4,8]],[[15,16],[23,42]]]
Input:
K = 2
P = [[1,1], [1,1], [1,1]]
Output:
[[[1,1]],[[1,1],[1,1]]]
Puntuación
Este es el código de golf , por lo que gana la respuesta más corta en bytes.
fuente
1
, todos los puntos del segundo tienen etiqueta,2
etc.)K=2, P = [[1,1], [1,1], [1,1]]
.Respuestas:
Matlab, 25 bytes
Dada una
n x 2
matriz (una fila por punto, por ejemplo[[4,8]; [15,16]; [23,42]; [-13.37,-12.1]; [666,-666]]
), esta función devuelve una lista de etiquetas para cada punto de entrada.fuente
C ++,
479474 bytes¡Solo ~ 20 veces más que Matlab!
Golfed
La entrada / salida al algoritmo es un conjunto de puntos (
struct P
) conx
yy
; y la salida es el mismo conjunto, con sui
conjunto para indicar el índice del clúster de salida en el que termina el punto.Ese extra
i
también se utiliza para identificar los grupos. En el bucle principal, el centroide más cercano a cada punto se encuentra ordenando una copia de los centroides actuales por proximidad a ese punto.Esto maneja casos degenerados (grupos vacíos) manteniendo la posición anterior de los centroides correspondientes (ver definición de
P::n
, que también devuelve la distancia al centroide anterior). Se podrían guardar algunos caracteres asumiendo que estos no aparecerán.Sin golf, con principal
fuente
#define R p){return
y cambiar el segundo argumento del
ap
para poder usarlo tres veces en total?J,
6054 bytesDefine un verbo auxiliar
p
que toma una lista de puntos y centroides y clasifica cada punto por el índice del centroide más cercano. Luego, utiliza eso para repetir el proceso de elegir un nuevo centroide tomando los promedios de los puntos en cada grupo hasta que converja, y luego para dividir los puntos para la salida.Uso
El valor de k se da como un entero en el LHS. La lista de puntos se da como una matriz 2d en el RHS. Aquí se especifica como una lista de puntos que se forma en una matriz 2d de 5 x 2. La salida será la etiqueta para qué grupo pertenece cada punto en el mismo orden que la entrada.
Si desea utilizar una semilla fija para obtener resultados reproducibles, reemplace la
?
con un?.
at(?#)
.Explicación
fuente
CJam (60 bytes)
Esta es una función que toma su entrada en la forma
k p
en la pila. Se supone que los puntos se representan con dobles, no con int. No asume implícitamente nada sobre la dimensión de los puntos, por lo que se agruparía igualmente bien en el espacio euclidiano 6-D que en el 2-D especificado.Demostración en línea
fuente
Mathematica
1412 bytesDado que los elementos integrados están permitidos, esto debería hacerlo.
Ejemplo
{{{4, 8}, {-13.37, -12.1}}, {{15, 16}, {23, 42}}, {{666, -666}}}
fuente
f = FindClusters
,f[something]
.Jalea , 24 bytes
Pruébalo en línea!
Utiliza características que se implementaron después de publicar este desafío. Supuestamente, esto ya no es no competitivo .
Explicación
fuente
R , 273 bytes
Pruébalo en línea!
Toma
P
como una matriz, conx
yy
coordenadas en la primera y segunda columna respectivamente. DevuelveP
con una primera columna agregada que indica el índice del clúster (entero).Tuve que redefinir
w
copiando la fuente dennet::which.is.max
para cumplir con el requisito de que el clúster se elija al azar en caso de empate. De lo contrario, usaríawhich.min
desdebase
un total de 210 bytes. Todavía hay espacio para jugar al golf, pero no quería ofuscarlo demasiado para dar a otros la oportunidad de detectar posibles problemas dentro de mi código.fuente
Julia 213 bytes
Devuelve una matriz de la misma longitud que
p
, con enteros que indican a qué clústerp
pertenece el elemento correspondiente .Creo que todavía hay bastante margen para optimizar la cuenta atrás del personaje.
(Por supuesto, podría usar el paquete Clustering.jl para hacerlo trivialmente)
fuente