Golf thuật toán K-nghĩa


10

K-mean là một thuật toán phân cụm không giám sát tiêu chuẩn, với một tập hợp các "điểm" và một số cụm K, sẽ gán mỗi "điểm" cho một trong các cụm K.

Mã giả của K-nghĩa

Lưu ý rằng có nhiều biến thể của K-nghĩa. Bạn phải thực hiện thuật toán tôi mô tả dưới đây. Bạn có thể có một số biến thể về thuật toán hoặc sử dụng các hàm dựng sẵn miễn là bạn sẽ nhận được kết quả tương tự như thuật toán này có cùng điểm ban đầu.

Trong thử thách này, tất cả các đầu vào sẽ là các điểm trên mặt phẳng 2D (mỗi điểm được biểu thị bằng tọa độ của nó theo x và 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    

Đầu vào và đầu ra

  • Bạn có thể đưa K và P qua STDINhoặc làm đối số hàm, v.v.
  • P và các điểm trong P có thể được biểu diễn bằng bất kỳ cấu trúc tự nhiên nào cho tập hợp / danh sách theo ngôn ngữ bạn chọn.
  • K là một số nguyên dương hoàn toàn.
  • Bạn có thể cho rằng đầu vào là hợp lệ.
  • Sẽ luôn có ít nhất K điểm trong P.
  • Bạn có thể xuất các cụm thành STDOUT, trả chúng từ một hàm, v.v.
  • Thứ tự của các cụm và thứ tự bên trong các cụm là không quan trọng. -Bạn có thể trả về các nhóm điểm để thể hiện các cụm hoặc mỗi điểm được gắn nhãn với một mã định danh cho cụm (ví dụ: một số nguyên).

Các trường hợp thử nghiệm

Vì các cụm kết quả phụ thuộc vào điểm ban đầu được chọn, nên bạn có thể không nhận được cùng một kết quả (hoặc kết quả giống nhau mỗi khi bạn chạy mã của mình).

Do đó, chỉ lấy đầu ra làm đầu ra ví dụ.

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

Chấm điểm

Đây là , vì vậy câu trả lời ngắn nhất bằng byte sẽ thắng.


Được xây dựng cho phép khi kết quả không thể phân biệt với thuật toán của bạn?
Martin Ender

@ MartinBüttner nếu bạn có thể biện minh rằng đã cho cùng một điểm ban đầu, nó sẽ hội tụ đến cùng một kết quả, vâng.
Gây tử vong vào

Chúng ta cũng có thể chấp nhận nhãn đầu ra của tư cách thành viên của một cụm cho mỗi điểm? (Ví dụ: tất cả các điểm của cụm đầu tiên có nhãn 1, tất cả các điểm của cụm thứ hai đều có nhãn, 2v.v.)
flawr

@flawr Vâng, điều này được chấp nhận.
Gây tử vong vào

Trường hợp thử nghiệm thoái hóa : K=2, P = [[1,1], [1,1], [1,1]].
Peter Taylor

Câu trả lời:


4

Matlab, 25 byte

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

Đưa ra một n x 2ma trận (một hàng cho mỗi điểm, ví dụ [[4,8]; [15,16]; [23,42]; [-13.37,-12.1]; [666,-666]]) các hàm này trả về một danh sách các nhãn cho mỗi điểm đầu vào.


5

C ++, 479 474 byte

Chỉ ~ 20 lần nhiều như Matlab!

Chơi gôn

#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]);}}

Đầu vào / đầu ra của thuật toán là một tập hợp các điểm ( struct P) với xy; và đầu ra là cùng một tập hợp, với tập hợp của chúng iđể chỉ ra chỉ số của cụm đầu ra mà điểm kết thúc.

Phần bổ sung đó icũng được sử dụng để xác định các cụm. Trong vòng lặp chính, trọng tâm gần nhất với mỗi điểm được tìm thấy bằng cách sắp xếp một bản sao của các tâm hiện tại theo khoảng cách gần với điểm đó.

Điều này xử lý các trường hợp suy biến (cụm trống) bằng cách giữ vị trí trước đó của tâm tương ứng (xem định nghĩa P::n, cũng trả về khoảng cách từ trước đến trung tâm). Một vài ký tự có thể được lưu bằng cách giả sử rằng chúng sẽ không mọc lên.

Ungolfed, với chính

#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;
}

Tôi biết tôi có thể bị trễ trong nhận xét này, nhưng bạn có thể xác định một macro #define R p){returnvà thay đổi đối số thứ hai thành lđể pbạn có thể sử dụng tổng cộng ba lần không?
Zacharý

4

J, 60 54 byte

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

Xác định một động từ trợ giúp plấy danh sách các điểm và tâm và phân loại từng điểm theo chỉ số của trọng tâm gần nhất. Sau đó, nó sử dụng điều đó để lặp lại quá trình chọn centroid mới bằng cách lấy trung bình của các điểm trong mỗi cụm cho đến khi nó hội tụ, và sau đó phân vùng các điểm cho đầu ra.

Sử dụng

Giá trị của k được đưa ra dưới dạng một số nguyên trên LHS. Danh sách các điểm được đưa ra dưới dạng mảng 2d trên RHS. Ở đây, nó được chỉ định là một danh sách các điểm được định hình lại thành mảng 2d 5 x 2. Đầu ra sẽ là nhãn cho cụm mỗi điểm thuộc cùng thứ tự với đầu vào.

Nếu bạn muốn sử dụng một hạt giống cố định cho kết quả có thể tái tạo, thay thế ?bằng một ?.tại (?#).

   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

Giải trình

[:(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

Tôi sẽ cho +1, nhưng tôi sợ rằng việc phá 3k của bạn sẽ nguyền rủa tôi.
NoOneIsHere

3

CJam (60 byte)

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

Đây là một hàm lấy đầu vào của nó ở dạng k ptrên ngăn xếp. Nó giả định rằng các điểm được thể hiện bằng gấp đôi, không phải ints. Nó không hoàn toàn giả định bất cứ điều gì về kích thước của các điểm, do đó, nó sẽ co cụm tốt như nhau trong không gian Euclide 6-D như trong 2-D được chỉ định.

Bản demo trực tuyến


2

Toán học 14 12 byte

Vì tích hợp được cho phép, điều này sẽ làm điều đó.

FindClusters

Thí dụ

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


Bạn không cần dấu ngoặc. f = FindClusters, f[something].
NoOneIsHere

ok, cảm ơn tôi không chắc chắn
DavidC

1

Thạch , 24 byte

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

Hãy thử trực tuyến!

Sử dụng các tính năng đã được thực hiện sau khi thử thách này được đăng. Giả sử, điều này không còn là không cạnh tranh .

Giải trình

_ÆḊ¥þ³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 byte

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)

Hãy thử trực tuyến!

Thực hiện Pdưới dạng ma trận, với xytọa độ trong cột thứ nhất và thứ hai tương ứng. Trả về Pvới một cột đầu tiên được thêm vào cho biết chỉ số cụm (số nguyên).

Tôi đã phải xác định lại wbằng cách sao chép nguồn từ nnet::which.is.maxđể phù hợp với yêu cầu cụm được chọn ngẫu nhiên trong trường hợp quan hệ. Nếu không, tôi sẽ sử dụng which.mintừ basetổng cộng 210 byte. Vẫn còn chỗ để chơi gôn nhưng tôi không muốn làm xáo trộn nó nhiều để cho người khác có cơ hội phát hiện ra các vấn đề có thể xảy ra trong mã của tôi.


0

Julia 213 byte

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

Trả về một mảng có cùng độ dài với p, với các số nguyên cho biết phần tử tương ứng pthuộc về cụm nào .

Tôi nghĩ vẫn còn một chút phạm vi hợp lý để tối ưu hóa việc đếm ngược ký tự.

(Tất nhiên tôi chỉ có thể sử dụng gói Clustering.jl để thực hiện nó một cách tầm thường)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.