15

Ho bisogno di raggruppare un semplice insieme di dati univariati in un numero predefinito di cluster. Tecnicamente sarebbe più vicino al binning o all'ordinamento dei dati poiché è solo 1D, ma il mio capo lo chiama clustering, quindi mi limiterò a seguire quel nome. Il metodo corrente utilizzato dal sistema in cui mi trovo è K-means, ma sembra eccessivo.Come si può utilizzare la stima della densità del kernel come metodo di clustering 1D in scikit?

Esiste un modo migliore per eseguire questa attività?

Le risposte ad alcuni altri post menzionano KDE (Kernel Density Estimation), ma questo è un metodo di stima della densità, come funzionerebbe?

Vedo come KDE restituisce una densità, ma come faccio a distinguere i dati in contenitori?

Come è possibile avere un numero fisso di contenitori indipendenti dai dati (è uno dei miei requisiti)?

In particolare, in che modo si potrebbe trarre vantaggio dall'utilizzo di scikit?

Il mio file di input appare come:

str ID  sls 
1   10 
2   11 
3   9 
4   23 
5   21 
6   11 
7   45 
8   20 
9   11 
10   12 

Voglio gruppo il numero SLS in cluster o bidoni, in modo tale che:

Cluster 1: [10 11 9 11 11 12] 
Cluster 2: [23 21 20] 
Cluster 3: [45] 

E il mio file di output sarà simile:

str ID  sls Cluster ID Cluster centroid 
    1  10  1    10.66 
    2  11  1    10.66 
    3   9  1    10.66 
    4  23  2    21.33 
    5  21  2    21.33 
    6  11  1    10.66 
    7  45  3    45 
    8  20  2    21.33 
    9  11  1    10.66 
    10  12  1    10.66 
+0

Qual è il problema con k-means? Prestazione? –

+0

kmeans è più efficiente di kde – lejlot

+0

@DavidMaust 1) Quando ho provato a eseguire k-means di sklearn su dati univariati, ho iniziato a ricevere errori. Ho dovuto ingannarlo facendolo raggruppare su dati 2D che erano copie identiche dei dati 1d originali. 2) Secondo questo [post] (http://stackoverflow.com/a/11516590/3967806) è una cattiva idea. –

risposta

24

Scrivi codice tu stesso. Quindi si adatta meglio al tuo problema!

Boilerplate: Non assumere mai il codice scaricato dalla rete per essere corretto o ottimale ... assicurarsi di capirlo completamente prima di utilizzarlo.

%matplotlib inline 

from numpy import array, linspace 
from sklearn.neighbors.kde import KernelDensity 
from matplotlib.pyplot import plot 

a = array([10,11,9,23,21,11,45,20,11,12]).reshape(-1, 1) 
kde = KernelDensity(kernel='gaussian', bandwidth=3).fit(a) 
s = linspace(0,50) 
e = kde.score_samples(s.reshape(-1,1)) 
plot(s, e) 

enter image description here

from scipy.signal import argrelextrema 
mi, ma = argrelextrema(e, np.less)[0], argrelextrema(e, np.greater)[0] 
print "Minima:", s[mi] 
print "Maxima:", s[ma] 
> Minima: [ 17.34693878 33.67346939] 
> Maxima: [ 10.20408163 21.42857143 44.89795918] 

i cluster, pertanto, sono

print a[a < mi[0]], a[(a >= mi[0]) * (a <= mi[1])], a[a >= mi[1]] 
> [10 11 9 11 11 12] [23 21 20] [45] 

e visivamente, abbiamo fatto questa scissione:

plot(s[:mi[0]+1], e[:mi[0]+1], 'r', 
    s[mi[0]:mi[1]+1], e[mi[0]:mi[1]+1], 'g', 
    s[mi[1]:], e[mi[1]:], 'b', 
    s[ma], e[ma], 'go', 
    s[mi], e[mi], 'ro') 

enter image description here

Abbiamo tagliato i marcatori rossi. I marcatori verdi sono le nostre migliori stime per i centri di cluster.

+0

Sarei restio a chiamare questo metodo meglio di k-means. Ciò comporta la selezione di una larghezza di banda arbitraria e quindi il calcolo di 50 stime di densità. Detto questo, non so se c'è un modo migliore per farlo con la stima della densità del kernel. –

+4

Non devi sapere k. Non si ottengono solo centri migliori (meno colpiti dai valori anomali) ma anche * suoni * che dividono i punti (non solo a metà strada). C'è molta letteratura sulla larghezza di banda come la regola di Silverman. Anche. chi si preoccupa di calcolare 50 stime di densità? Puoi precomputare il kernel e farlo in una convoluzione veloce. –

+0

Aggiungerò anche che questo è un metodo di ridimensionamento particolarmente lineare e non lineare per il clustering 1D. – Matthew

Problemi correlati