K-means é um algoritmo de clustering não supervisionado padrão que, dado um conjunto de "pontos" e um número de clusters K, atribuirá cada "ponto" a um dos K clusters.
Pseudo-código de K-significa
Observe que existem muitas variantes de médias K. Você precisa implementar o algoritmo que estou descrevendo abaixo. Você pode ter alguma variação no algoritmo ou usar built-ins desde que obtenha o mesmo resultado que esse algoritmo, considerando os mesmos pontos iniciais.
Neste desafio, todas as entradas serão pontos no plano 2D (cada ponto é representado por suas coordenadas em 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 e saídas
- Você pode passar K e P através
STDIN
ou como argumento de função, etc. - P e os pontos em P podem ser representados usando qualquer estrutura natural para conjuntos / listas no seu idioma de escolha.
- K é um número inteiro estritamente positivo.
- Você pode assumir que as entradas são válidas.
- Sempre haverá pelo menos K pontos em P.
- Você pode enviar os clusters
STDOUT
, retorná-los de uma função etc. - A ordem dos clusters e a ordem dentro dos clusters não é importante. -Você pode retornar grupos de pontos para representar clusters ou cada ponto rotulado com um identificador para o cluster (por exemplo, um número inteiro).
Casos de teste
Como os clusters resultantes dependem de quais pontos foram escolhidos inicialmente, nem todos poderão obter os mesmos resultados (ou o mesmo resultado sempre que executar seu código).
Portanto, tome apenas a saída como exemplo de saída.
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]]]
Pontuação
Isso é código-golfe , então a resposta mais curta em bytes vence.
fonte
1
, todos os pontos do segundo uma etiqueta tem2
etc)K=2, P = [[1,1], [1,1], [1,1]]
.Respostas:
Matlab, 25 bytes
Dada uma
n x 2
matriz (uma linha por ponto, por exemplo[[4,8]; [15,16]; [23,42]; [-13.37,-12.1]; [666,-666]]
), essas funções retornam uma lista de rótulos para cada ponto de entrada.fonte
C ++,
479474 bytesApenas ~ 20x mais do que o Matlab!
Golfe
A entrada / saída para o algoritmo é um conjunto de pontos (
struct P
) comx
ey
; e a saída é o mesmo conjunto, com os respectivosi
para indicar o índice do cluster de saída em que o ponto termina.Esse extra
i
também é usado para identificar os clusters. No loop principal, o centróide mais próximo de cada ponto é encontrado, classificando uma cópia dos centróides atuais por proximidade a esse ponto.Isso lida com casos degenerados (grupos vazios) mantendo a posição anterior dos centróides correspondentes (consulte a definição de
P::n
, que também retorna a distância entre os centróides anteriores). Alguns caracteres podem ser salvos assumindo que eles não aparecerão.Ungolfed, com principal
fonte
#define R p){return
e alterar o segundo argumento del
parap
para usá-lo três vezes no total?J,
6054 bytesDefine um verbo auxiliar
p
que pega uma lista de pontos e centróides e classifica cada ponto pelo índice do centróide mais próximo. Em seguida, ele usa isso para repetir o processo de escolha de um novo centróide, tomando as médias dos pontos em cada cluster até convergir e, em seguida, particionando os pontos para a saída.Uso
O valor de k é dado como um número inteiro no LHS. A lista de pontos é apresentada como uma matriz 2D no RHS. Aqui, ele é especificado como uma lista de pontos que são remodelados em uma matriz 2d de 5 x 2. A saída será o rótulo para o qual cluster cada ponto pertence na mesma ordem que a entrada.
Se você deseja usar uma semente fixa para obter resultados reproduzíveis, substitua
?
por?.
a(?#)
.Explicação
fonte
CJam (60 bytes)
Esta é uma função que recebe sua entrada no formulário
k p
na pilha. Assume que os pontos são representados com duplos, não ints. Ele não assume implicitamente nada sobre a dimensão dos pontos, portanto se agruparia igualmente bem no espaço euclidiano 6-D como no 2-D especificado.Demonstração online
fonte
Mathematica
1412 bytesComo os embutidos são permitidos, isso deve ser feito.
Exemplo
{{{4, 8}, {-13,37, -12,1}}, {{15, 16}, {23, 42}}, {{666, -666}}}
fonte
f = FindClusters
,f[something]
.Gelatina , 24 bytes
Experimente online!
Usa os recursos implementados após o lançamento deste desafio. Supostamente, isso não é mais uma competição .
Explicação
fonte
R , 273 bytes
Experimente online!
Toma
P
como matriz, comx
ey
coordenadas na primeira e na segunda coluna, respectivamente. RetornaP
com uma primeira coluna adicionada que indica o índice do cluster (inteiro).Eu tive que redefinir
w
copiando a fonte dennet::which.is.max
para estar em conformidade com o requisito de que o cluster seja escolhido aleatoriamente em caso de vínculo. Caso contrário, eu usaria awhich.min
partirbase
de um total de 210 bytes. Ainda há espaço para jogar golfe, mas eu não queria ofuscar muito para dar aos outros a chance de detectar possíveis problemas no meu código.fonte
Julia 213 bytes
Retorna uma matriz do mesmo comprimento que
p
, com números inteiros indicando a qual cluster o elemento correspondentep
pertence.Acho que ainda há um pouco de escopo para otimizar a contagem de caracteres.
(É claro que eu poderia usar o pacote Clustering.jl para fazer isso trivialmente)
fonte