Golf K-algoritması


10

K-araçları , bir dizi "nokta" ve bir dizi K kümesi verildiğinde, her bir "noktayı" K kümelerinden birine atayacak olan standart bir denetimsiz kümeleme algoritmasıdır.

K-anlamlarının Sahte Kodu

K-araçlarının birçok varyantı olduğunu unutmayın. Aşağıda açıkladığım algoritmayı uygulamalısınız. Algoritmada bazı farklılıklar olabilir veya aynı başlangıç ​​noktaları verildiğinde bu algoritma ile aynı sonucu alacağınız sürece yerleşik kullanabilirsiniz.

Bu zorlukta, tüm girdiler 2B düzlemdeki noktalar olacaktır (her nokta x ve y'deki koordinatları ile temsil edilir).

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    

Girdiler ve çıktılar

  • K ve P'yi STDINveya bir işlev argümanı vb.
  • P ve P'deki noktalar, seçtiğiniz dildeki set / listeler için doğal olan herhangi bir yapı kullanılarak temsil edilebilir.
  • K kesinlikle pozitif bir tamsayıdır.
  • Girişlerin geçerli olduğunu varsayabilirsiniz.
  • P'de her zaman en az K puanı olacaktır.
  • Kümeleri çıktı alabilir, STDOUTbir işlevden döndürebilir vb.
  • Kümelerin sıralaması ve kümelerin içindeki sıralamalar önemsizdir. -Kümeleri temsil etmek için nokta gruplarını veya küme için tanımlayıcı ile etiketlenmiş her noktayı (örneğin bir tamsayı) döndürebilirsiniz.

Test senaryoları

Ortaya çıkan kümeler başlangıçta hangi noktaların seçildiğine bağlı olduğundan, aynı sonuçları (veya kodunuzu her çalıştırdığınızda aynı sonucu) alamayabilirsiniz.

Bu nedenle, çıktıyı yalnızca örnek çıktı olarak alın.

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

puanlama

Bu , bu yüzden bayttaki en kısa cevap kazanır.


Sonuçlar algoritmanızdan ayırt edilemediğinde yerleşiklere izin veriliyor mu?
Martin Ender

@ MartinBüttner, eğer aynı başlangıç ​​puanları verildiğini haklı çıkarırsanız, aynı sonuca yakınsa, evet.
7'de öldürme

Her nokta için bir küme üyeliğinin etiketlerinin çıkarılması da kabul edilebilir mi? (Örneğin, ilk kümenin 1tüm noktalarının etiketi , ikincisinin tüm noktalarının etiketi 2vb.
Vardır

@flawr Evet, bu kabul edilebilir.
11'de öldürme

Dejenere test durumu: K=2, P = [[1,1], [1,1], [1,1]].
Peter Taylor

Yanıtlar:


4

Matlab, 25 bayt

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

Bir n x 2matris (nokta başına bir satır gibi) verildiğinde, [[4,8]; [15,16]; [23,42]; [-13.37,-12.1]; [666,-666]]bu işlevler her giriş noktası için bir etiket listesi döndürür.


5

C ++, 479 bayt

Matlab kadar sadece ~ 20x!

golfed

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

Algoritma, girdi / çıktı noktası (bir dizi struct P) ile xve y; ve çıktı aynı küme, onların inoktası noktanın bittiği çıktı kümesinin dizinini gösterecek şekilde ayarlanmış.

Bu ekstra i, kümeleri tanımlamak için de kullanılır. Ana döngüde, her noktaya en yakın centroid, mevcut sentroidlerin bir kopyasının o noktaya yakınlığına göre sıralanmasıyla bulunur.

Bu, ilgili sentroidlerin önceki pozisyonlarını koruyarak dejenere vakaları (boş kümeler) işler (bkz. P::n ayrıca . Bunların kırpılmayacağı varsayılarak birkaç karakter kaydedilebilir.

Ungolfed, ana ile

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

Ben bu yorumunda geç olabilir biliyorum ama bir makro tanımlayabiliriz #define R p){returnve ikinci argüman değiştirmek liçin ptoplam bunu üç defa kullanabilirsiniz böylece?
Zacharý

4

J, 60 54 bayt

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

Bir yardımcı fiili tanımlar pNokta ve sentroidlerin bir listesini alan ve her noktayı en yakın sentroidin indeksine göre sınıflandıran . Daha sonra, her kümedeki noktaların ortalamalarını birleşene kadar ortalamalarını alarak yeni centroid seçme işlemini tekrarlamak ve daha sonra çıktı için noktaları bölmek için kullanır.

kullanım

Değeri k lhs bir tamsayı olarak verilir. Nokta listesi RHS'de 2d dizisi olarak verilir. Burada, 5 x 2'lik bir 2d dizisine yeniden şekillendirilen noktaların bir listesi olarak belirtilir. Çıktı, her bir noktanın kümeyle girişle aynı sırayla ait olduğu etiket olacaktır.

Tekrarlanabilir sonuçlar için sabit bir tohum kullanmak isterseniz ?, 'yi bir ?.at ile değiştirin (?#).

   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

açıklama

[:(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 verirdim, ama 3k'nizi kırmanın beni lanetleyeceğinden korkuyorum.
NoOneIsHere

3

CJam (60 bayt)

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

Bu, girdisini k pyığındaki formda alan bir işlevdir . Noktaların ints ile değil, çiftlerle temsil edildiğini varsayar. Örtük olarak noktaların boyutu hakkında hiçbir şey varsaymaz, bu nedenle belirtilen 2-D'deki gibi 6-D Öklid uzayında eşit derecede kümelenir.

Çevrimiçi demo


2

Mathematica 14 12 bayt

Yerleşik yapılara izin verildiğinden, bunu yapmalıdır.

FindClusters

Misal

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


Parantezlere ihtiyacınız yok. f = FindClusters, f[something].
NoOneIsHere

tamam, teşekkürler emin değildim.
DavidC

1

Jöle , 24 bayt

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

Çevrimiçi deneyin!

Bu sorun gönderildikten sonra uygulanan özellikleri kullanır. Sözde, bu artık rekabet etmiyor .

açıklama

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

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)

Çevrimiçi deneyin!

Alır Pile, bir matris olarak xve ysırasıyla birinci ve ikinci sütunda koordinatlar. İade Pbir birinci sütun ile küme endeksi (tam sayı) işaret eden ilave edildi.

Bağlar halinde kümenin rastgele seçilmesi şartına uymak için wkaynağı kopyalayarak yeniden tanımlamak zorunda kaldım nnet::which.is.max. Aksi halde ben kullanırım which.minden base210 bayt olmak üzere toplam. Hala golf için yer var ama diğerleri kodumu içinde olası sorunları tespit etmek için bir şans vermek için çok şaşırtmak istemiyordu.


0

Julia 213 bayt

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

pKarşılık gelen öğenin hangi kümeye pait olduğunu gösteren tamsayılarla aynı uzunlukta bir dizi döndürür .

Karakter geri sayımını optimize etmek için hala oldukça kapsamlı bir alan olduğunu düşünüyorum.

(Elbette sadece Clustering.jl paketini önemsiz yapmak için kullanabilirim)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.