K-średnich jest standardowym nie nadzorowanym algorytmem grupowania, który, biorąc pod uwagę zestaw „punktów” i pewną liczbę klastrów K, przypisze każdy „punkt” do jednego z K klastrów.
Pseudokod K-średnich
Zauważ, że istnieje wiele wariantów K-średnich. Musisz zaimplementować algorytm, który opisuję poniżej. Możesz mieć pewne różnice w algorytmie lub użyć wbudowanych, o ile uzyskasz taki sam wynik jak ten algorytm, mając te same punkty początkowe.
W tym wyzwaniu wszystkie dane wejściowe będą punktami na płaszczyźnie 2D (każdy punkt jest reprezentowany przez jego współrzędne w xiy).
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
Wejścia i wyjścia
- Możesz wziąć K i P przez
STDIN
, lub jako argument funkcji itp. - P i punkty w P można przedstawić za pomocą dowolnej struktury, która jest naturalna dla zestawu / list w wybranym języku.
- K jest ściśle dodatnią liczbą całkowitą.
- Możesz założyć, że dane wejściowe są prawidłowe.
- Zawsze będzie co najmniej K punktów w P.
- Możesz wyprowadzać klastry do
STDOUT
, zwracać je z funkcji itp. - Kolejność klastrów i kolejność wewnątrz klastrów jest nieistotna. -Można albo zwrócić grupy punktów, które reprezentują klastry, albo każdy punkt oznaczony identyfikatorem klastra (np. Liczba całkowita).
Przypadki testowe
Ponieważ powstałe klastry zależą od tego, które punkty zostały początkowo wybrane, nie wszyscy mogą uzyskać takie same wyniki (lub ten sam wynik przy każdym uruchomieniu kodu).
Dlatego dane wyjściowe należy traktować tylko jako dane wyjściowe.
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]]]
Punktacja
To jest golf golfowy , więc wygrywa najkrótsza odpowiedź w bajtach.
źródło
1
, wszystkie punkty drugiego klastra mają etykietę2
itp.)K=2, P = [[1,1], [1,1], [1,1]]
.Odpowiedzi:
Matlab, 25 bajtów
Biorąc pod uwagę
n x 2
macierz (np. Jeden wiersz na punkt[[4,8]; [15,16]; [23,42]; [-13.37,-12.1]; [666,-666]]
), funkcja ta zwraca listę etykiet dla każdego punktu wejściowego.źródło
C ++,
479474 bajtyTylko ~ 20x więcej niż Matlab!
Grał w golfa
Wejście / wyjście algorytmu jest zbiorem punktów (
struct P
) zx
iy
; a dane wyjściowe są tego samego zestawu, z ichi
zestawem wskazującym indeks klastra wyjściowego, w którym kończy się punkt.Dodatek
i
ten służy również do identyfikacji klastrów. W głównej pętli centroid najbliżej każdego punktu znajduje się poprzez posortowanie kopii bieżących centroidów według odległości od tego punktu.To obsługuje przypadki zdegenerowane (puste klastry) poprzez zachowanie poprzedniej pozycji odpowiadających centroidów (patrz definicja
P::n
, która również zwraca odległość do poprzedniej centroidy). Można zapisać kilka znaków, zakładając, że nie pojawią się one.Bez golfa, z głównym
źródło
#define R p){return
i zmienić drugi argumentl
nap
, abyś mógł użyć go trzykrotnie?J,
6054 bajtówDefiniuje czasownik pomocniczy,
p
który pobiera listę punktów i centroidów i klasyfikuje każdy punkt według indeksu najbliższego środka ciężkości. Następnie używa tego, aby powtórzyć proces wyboru nowego środka ciężkości, biorąc średnie wartości punktów w każdym skupieniu, aż się zbiegnie, a następnie dzieląc punkty na dane wyjściowe.Stosowanie
Wartość k jest podana jako liczba całkowita na LHS. Lista punktów jest podana jako tablica 2d na RHS. Tutaj jest określony jako lista punktów, które są przekształcane w tablicę 2d o wymiarach 5 x 2. Wyjście będzie etykietą, dla której klaster każdy punkt należy w tej samej kolejności co dane wejściowe.
Jeśli pragniesz użyć stałego materiału siewnego dla powtarzalnych wyników, wymienić
?
z?.
na(?#)
.Wyjaśnienie
źródło
CJam (60 bajtów)
Jest to funkcja, która przyjmuje dane wejściowe w formie
k p
stosu. Zakłada się, że punkty są reprezentowane przez podwójne, a nie ints. Nie zakłada domyślnie niczego o wymiarze punktów, więc skupiałby się równie dobrze w 6-D przestrzeni euklidesowej, jak w określonej 2-D.Demo online
źródło
Mathematica
1412 bajtówPonieważ wbudowane są dozwolone, powinno to zrobić.
Przykład
{{{4, 8}, {-13,37, -12,1}}, {{15, 16}, {23, 42}}, {{666, -666}}}
źródło
f = FindClusters
,f[something]
.Galaretka , 24 bajty
Wypróbuj online!
Korzysta z funkcji zaimplementowanych po opublikowaniu tego wyzwania. Podobno nie jest to już niekonkurencyjne .
Wyjaśnienie
źródło
R , 273 bajtów
Wypróbuj online!
Staje się
P
jako matryca zx
iy
współrzędne w pierwszej i drugiej kolumnie, odpowiednio. ZwracaP
z dodaną pierwszą kolumną, która wskazuje indeks klastra (liczba całkowita).Musiałem przedefiniować
w
, kopiując źródło z,nnet::which.is.max
aby dostosować się do wymogu losowego wybierania klastra w przypadku powiązań. W przeciwnym razie użyłbymwhich.min
zbase
w sumie 210 bajtów. Wciąż jest pole do gry w golfa, ale nie chciałem zbytnio zaciemniać go, aby dać innym szansę dostrzeżenia możliwych problemów w moim kodzie.źródło
Julia 213 bajtów
Zwraca tablicę o tej samej długości co
p
, z liczbami całkowitymi wskazującymi, do którego klastra należy odpowiedni elementp
.Myślę, że wciąż istnieje spory zakres, aby zoptymalizować odliczanie postaci.
(Oczywiście mogę po prostu użyć pakietu Clustering.jl, aby zrobić to trywialnie)
źródło