K- 평균 알고리즘 골프


10

K- 평균 은 표준 비 감독 클러스터링 알고리즘으로, "포인트"세트와 여러 클러스터 K가 주어지면 각 "포인트"를 K 클러스터 중 하나에 할당합니다.

K- 평균의 의사 코드

K- 평균에는 많은 변형이 있습니다. 아래에서 설명하는 알고리즘을 구현해야합니다. 동일한 초기 포인트가 주어지면이 알고리즘과 동일한 결과를 얻는 한 알고리즘에 약간의 변형이 있거나 내장 기능을 사용할 수 있습니다.

이 문제에서 모든 입력은 2D 평면의 점이됩니다 (각 점은 x와 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    

입력 및 출력

  • K 및 P를 통해 STDIN또는 함수 인수 등으로 사용할 수 있습니다.
  • P와 P의 점은 선택한 언어의 세트 / 목록에 자연스러운 구조를 사용하여 표현할 수 있습니다.
  • K는 양의 정수입니다.
  • 입력이 유효하다고 가정 할 수 있습니다.
  • P에는 항상 최소 K 점이 있습니다.
  • 에 클러스터를 출력 STDOUT하거나 함수에서 클러스터 등을 반환 할 수 있습니다.
  • 클러스터의 순서와 클러스터 내부의 순서는 중요하지 않습니다. -군집을 나타 내기 위해 점 그룹을 반환하거나 군집 식별자 (예 : 정수)로 레이블 된 각 점을 반환 할 수 있습니다.

테스트 사례

결과 군집은 처음에 선택한 점에 따라 다르므로 코드를 실행할 때마다 같은 결과를 얻지 못할 수도 있습니다.

따라서 출력을 예제 출력으로 만 사용하십시오.

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]]]

채점

이것은 이므로 바이트 단위의 최단 답변이 이깁니다.


알고리즘과 결과를 구별 할 수없는 경우 내장 기능이 허용됩니까?
Martin Ender

@ MartinBüttner 동일한 초기 포인트가 주어지면 동일한 결과로 수렴한다는 것을 정당화 할 수 있다면 그렇습니다.
치명적

각 포인트마다 클러스터 멤버쉽 레이블을 출력하는 것이 허용됩니까? (예 : 첫 번째 클러스터의 1모든 지점 에는 레이블 이 있고 두 번째 클러스터의 모든 지점에는 레이블이 있습니다. 2)
flawr

@flawr 예, 허용됩니다.
페이탈 라이즈

테스트 사례를 분해하십시오 K=2, P = [[1,1], [1,1], [1,1]].
피터 테일러

답변:


4

Matlab, 25 바이트

@(x,k)kmeans(x,k,'S','u')

n x 2행렬 (예 : 점당 하나의 행 [[4,8]; [15,16]; [23,42]; [-13.37,-12.1]; [666,-666]])이 주어지면 이 함수는 각 입력 점에 대한 레이블 목록을 반환합니다.


5

C ++, 479 474 바이트

Matlab보다 ~ 20 배만!

골프

#define V vector<P>
#define f float
struct P{f x,y,i=0;f d(P&p){return(p.x-x)*(p.x-x)+(p.y-y)*(p.y-y);}f n(P&p){return i?x/=i,y/=i,d(p):x=p.x,y=p.y,0;}f a(P&p){x+=p.x,y+=p.y,i++;}};P z;int l(P a,P b){return a.d(z)<b.d(z);}f m(f k,V&p){f s=p.size(),i,j=0,t=1;V c(k),n=c,d;for(random_shuffle(p.begin(),p.end());j<k;c[j].i=j++)c[j]=p[j];for(;t;c=n,n=V(k)){for(i=0;i<s;i++)d=c,z=p[i],sort(d.begin(),d.end(),l),j=d[0].i,p[i].i=j,n[j].a(p[i]);for(j=t=0;j<k;j++)t+=n[j].n(c[j]);}}

알고리즘에 대한 입 / 출력은 및 ( struct P와)을 갖는 포인트 ( ) 의 세트입니다 . 그리고 출력은 포인트가 끝나는 출력 클러스터의 인덱스를 나타 내기 위해로 설정되어 있습니다.xyi

이 추가 정보 i는 클러스터를 식별하는 데에도 사용됩니다. 메인 루프에서 각 점에 가장 가까운 중심은 현재 중심의 사본을 해당 점에 근접하여 정렬하여 찾습니다.

이것은 대응하는 중심의 이전 위치를 유지함으로써 퇴화 사례 (빈 군집)를 처리합니다 (의 정의를 참조하십시오 P::n. 자르지 않을 것이라고 가정하면 몇 개의 문자를 절약 할 수 있습니다.

메인과 함께 언 골프

#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;

#define V vector<P>
#define f float
struct P{
    f x,y,i=0;
    f d(P&p){return(p.x-x)*(p.x-x)+(p.y-y)*(p.y-y);} // distance squared
    f n(P&p){return i?x/=i,y/=i,d(p):x=p.x,y=p.y,0;} // normalize-or-reset
    f a(P&p){x+=p.x,y+=p.y,i++;}                     // add coordinates
};
P z;int l(P a,P b){return a.d(z)<b.d(z);}            // closer-to-z comparator 
f m(f k,V&p){
    f s=p.size(),i,j=0,t=1;V c(k),n=c,d;
    for(random_shuffle(p.begin(),p.end());j<k;c[j].i=j++)
        c[j]=p[j];                                // initial random assignment
    for(;t;c=n,n=V(k)){                           
        for(i=0;i<s;i++)                          // assign to clusters
            d=c,z=p[i],sort(d.begin(),d.end(),l),
            j=d[0].i,p[i].i=j,n[j].a(p[i]);       // and add those coords
        for(j=t=0;j<k;j++)t+=n[j].n(c[j]);        // normalize & count changes
    }        
}

int main(int argc, char **argv) {
    srand((unsigned long)time(0));

    int k;
    V p;
    sscanf(argv[1], "%d", &k);
    printf("Input:\n");
    for (int i=2,j=0; i<argc; i+=2, j++) {
        P n;
        sscanf(argv[i], "%f", &(n.x));
        sscanf(argv[i+1], "%f", &(n.y));
        p.push_back(n);
        printf("%d : %f,%f\n", j, p[j].x, p[j].y);
    }

    m(k,p);
    printf("Clusters:\n");
    for (int q=0; q<k; q++) {
        printf("%d\n", q);
        for (unsigned int i=0; i<p.size(); i++) {
            if (p[i].i == q) printf("\t%f,%f (%d)\n", p[i].x, p[i].y, i);
        }
    }
    return 0;
}

나는이 의견에 늦을 수도 있습니다 알고 있지만, 당신은 매크로를 정의 할 수 있습니다 #define R p){return와의 두 번째 인수 변경 lp총 당신이 그것을 세 번을 사용할 수 있도록를?
Zacharý

4

J, 60 54 바이트

p=:[:(i.<./)"1([:+/&.:*:-)"1/
]p](p(+/%#)/.[)^:_(?#){]

p점과 중심 목록을 가져오고 가장 가까운 중심의 색인으로 각 점을 분류 하는 도우미 동사 를 정의합니다 . 그런 다음이를 사용하여 각 군집의 평균 점을 수렴 할 때까지 점의 평균을 취하여 새 중심을 선택하는 과정을 반복 한 다음 점을 분할하여 출력합니다.

용법

k 값은 LHS에서 정수로 제공됩니다. 포인트 목록은 RHS에서 2D 배열로 제공됩니다. 여기서는 5 x 2의 2d 배열로 재구성되는 점 목록으로 지정됩니다. 출력은 각 점이 입력과 동일한 순서로 속하는 클러스터의 레이블이됩니다.

당신이 재현 가능한 결과에 대한 고정 된 종자를 사용하고자하는 경우, 교체 ?A를을 ?.(?#).

   p =: [:(i.<./)"1([:+/&.:*:-)"1/
   f =: ]p](p(+/%#)/.[)^:_(?#){]
   3 f (5 2 $ 4 8 15 16 23 42 _13.37 _12.1 666 _666)
0 1 1 0 2

설명

[:(i.<./)"1([:+/&.:*:-)"1/  Input: points on LHS, centroids on RHS
           (          )"1/  Form a table between each point and centroid and for each
                     -        Find the difference elementwise
            [:     *:         Square each
              +/&.:           Reduce using addition
                              Apply the inverse of square (square root) to that sum
[:(     )"1                 For each row of that table
     <./                      Reduce using min
   i.                         Find the index of the minimum in that row
                            Returns a list of indices for each point that shows
                            which centroid it belongs to

]p](p(+/%#)/.[)^:_(?#){]  Input: k on LHS, points on RHS
                    #     Count the number of points
                   ?      Choose k values in the range [0, len(points))
                          without repetition
                       ]  Identity function, get points
                      {   Select the points at the indices above
  ]                       Identity function, get points
   (         )^:_         Repeat until convergence
    p                       Get the labels for each point
             [              Identity function, get points
           /.               Partition the points using the labels and for each
      +/                      Take the sums of points elementwise
         #                    Get the number of points
        %                     Divide sum elementwise by the count
                            Return the new values as the next centroids
]                         Identity function, get points
 p                        Get the labels for each point and return it

나는 +1을 줄 것이지만, 당신의 3k를 깨 뜨리면 저를 저주 할까 두렵습니다.
NoOneIsHere7

3

CJam (60 바이트)

{:Pmr<1/2P,#{:z{_:+\,/}f%:C,{P{C\f{.-Yf#:+}_:e<#1$=},\;}%}*}

k p스택 형태로 입력을받는 함수입니다 . 포인트가 int가 아닌 double로 표시된다고 가정합니다. 점의 차원에 대해 암시 적으로 아무것도 가정하지 않으므로 지정된 2 차원에서와 같이 6 차원 유클리드 공간에서 동일하게 클러스터됩니다.

온라인 데모


2

Mathematica 14 12 바이트

내장이 허용되므로 그렇게해야합니다.

FindClusters

FindClusters[{{4, 8}, {15, 16}, {23, 42}, {-13.37, -12.1}, {666, -666}}, 3]

{{{4, 8}, {-13.37, -12.1}}, {{15, 16}, {23, 42}}, {{666, -666}}}


괄호가 필요하지 않습니다. f = FindClusters, f[something].
NoOneIsHere7

알았어, 고마워
DavidC

1

젤리 , 24 바이트

_ÆḊ¥þ³i"Ṃ€$
ẊḣµÇÆmƙ³µÐLÇ

온라인으로 사용해보십시오!

이 챌린지가 게시 된 후 구현 된 기능을 사용합니다. 아마도 이것은 더 이상 경쟁 이 아닙니다 .

설명

_ÆḊ¥þ³i"Ṃ€$  Helper link. Input: array of points
             (Classify) Given a size-k array of points, classifies
             each point in A to the closet point in the size-k array
    þ        Outer product with
     ³       All points, P
   ¥         Dyadic chain
_              Subtract
 ÆḊ            Norm
          $  Monadic chain
      i"     Find first index, vectorized
        Ṃ€   Minimum each

ẊḣµÇÆmƙ³µÐLÇ  Main link. Input: array of points P, integer k
  µ           Start new monadic chain
Ẋ               Shuffle P
 ḣ              Take the first k
        µ     Start new monadic chain
   Ç            Call helper (Classify)
      ƙ         Group with those values the items of
       ³        All points, P
    Æm            Take the mean of each group
         ÐL   Repeat that until the results converge
           Ç  Call helper (Classify)

1

R , 273 바이트

function(K,P,C=P[sample(nrow(P),K),]){while(T){D=C
U=sapply(1:nrow(P),function(i)w(dist(rbind(P[i,],C))[1:K]))
C=t(sapply(1:K,function(i)colMeans(P[U==i,,drop=F])))
T=isTRUE(all.equal(C,D))}
cbind(U,P)}
w=function(x,y=seq_along(x)[x==min(x)])"if"(length(y)>1,sample(y,1),y)

온라인으로 사용해보십시오!

P와 매트릭스로서 xy , 각각 제 1 및 제 2 열의 좌표. P클러스터 인덱스 (정수)를 나타내는 첫 번째 열을 추가하여 반환 합니다.

관계가있는 경우 클러스터를 임의로 선택해야한다는 요구 사항에 맞게 w소스를 복사하여 재정의 nnet::which.is.max해야했습니다. 그렇지 않으면 내가 사용하는 것이 which.min에서 base210 바이트의 총. 여전히 골프의 여지가 있지만 다른 사람들이 내 코드 내에서 가능한 문제를 발견 할 수있는 기회를 제공하기 위해 그것을 난독 화하고 싶지 않았습니다.


0

줄리아 213 바이트

function f(p,k)
A=0
P=size(p,1)
c=p[randperm(P)[1:k],:]
while(true)
d=[norm(c[i]-p[j]) for i in 1:k, j in 1:P]
a=mapslices(indmin,d,1)
a==A&&return a
A=a
c=[mean(p[vec(a.==i),:],1) for i in 1:k]
end
end

와 같은 길이의 배열을 반환합니다. p정수는 해당 요소가 p속하는 클러스터를 나타냅니다 .

캐릭터 카운트 다운을 최적화 할 수있는 여지가 여전히 있다고 생각합니다.

(물론 Clustering.jl 패키지를 사용하여 간단하게 할 수 있습니다)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.