2015-02-09 28 views
10

Ho un array di valori 13.876 (13.876) tra 0 e 1. Vorrei applicare sklearn.cluster.KMeans solo a questo vettore per trovare i diversi cluster in cui sono raggruppati i valori. Tuttavia, sembra che KMean lavori con un array multidimensionale e non con quelli unidimensionali. Immagino che ci sia un trucco per farlo funzionare ma non so come. Ho visto che KMeans.fit() accetta "X: array simile o matrici sparse, di forma = (N_SAMPLES, n_features)", ma vuole la n_samples di essere più grande di unScikit-learn: come eseguire KMeans su un array monodimensionale?

Ho provato a mettere il mio allineamento su un np.zeros() matrix ed eseguire KMeans, ma quindi sta mettendo tutti i valori non nulli sulla classe 1 e il resto sulla classe 0.

Qualcuno può aiutare a eseguire questo algoritmo su una matrice monodimensionale? Grazie mille!

risposta

18

si hanno molti campioni di 1 funzione, in modo da poter rimodellare la matrice a (13.876, 1) utilizzando di reshape NumPy:

from sklearn.cluster import KMeans 
import numpy as np 
x = np.random.random(13876) 

km = KMeans() 
km.fit(x.reshape(-1,1)) # -1 will be calculated to be 13876 here 
+0

Ha funzionato come un fascino, questo dettaglio mi ha bloccato per un'ora! – iamgin

+0

Se si utilizza MiniBatchKmeans su questo tipo di dati di forma, si ottengono risultati molto diversi. È questo comportamento previsto ?? – marscher

+0

questo è correlato allo stato casuale. Se lo si risolve, si ottengono gli stessi risultati. – marscher

3

Leggi Jenks Natural Breaks. Funzione in Python ha trovato il link di un articolo:

def get_jenks_breaks(data_list, number_class): 
    data_list.sort() 
    mat1 = [] 
    for i in range(len(data_list) + 1): 
     temp = [] 
     for j in range(number_class + 1): 
      temp.append(0) 
     mat1.append(temp) 
    mat2 = [] 
    for i in range(len(data_list) + 1): 
     temp = [] 
     for j in range(number_class + 1): 
      temp.append(0) 
     mat2.append(temp) 
    for i in range(1, number_class + 1): 
     mat1[1][i] = 1 
     mat2[1][i] = 0 
     for j in range(2, len(data_list) + 1): 
      mat2[j][i] = float('inf') 
    v = 0.0 
    for l in range(2, len(data_list) + 1): 
     s1 = 0.0 
     s2 = 0.0 
     w = 0.0 
     for m in range(1, l + 1): 
      i3 = l - m + 1 
      val = float(data_list[i3 - 1]) 
      s2 += val * val 
      s1 += val 
      w += 1 
      v = s2 - (s1 * s1)/w 
      i4 = i3 - 1 
      if i4 != 0: 
       for j in range(2, number_class + 1): 
        if mat2[l][j] >= (v + mat2[i4][j - 1]): 
         mat1[l][j] = i3 
         mat2[l][j] = v + mat2[i4][j - 1] 
     mat1[l][1] = 1 
     mat2[l][1] = v 
    k = len(data_list) 
    kclass = [] 
    for i in range(number_class + 1): 
     kclass.append(min(data_list)) 
    kclass[number_class] = float(data_list[len(data_list) - 1]) 
    count_num = number_class 
    while count_num >= 2: # print "rank = " + str(mat1[k][count_num]) 
     idx = int((mat1[k][count_num]) - 2) 
     # print "val = " + str(data_list[idx]) 
     kclass[count_num - 1] = data_list[idx] 
     k = int((mat1[k][count_num] - 1)) 
     count_num -= 1 
    return kclass 

Uso e visualizzazione:

import numpy as np 
import matplotlib.pyplot as plt 

def get_jenks_breaks(...):... 

x = np.random.random(30) 
breaks = get_jenks_breaks(x, 5) 

for line in breaks: 
    plt.plot([line for _ in range(len(x))], 'k--') 

plt.plot(x) 
plt.grid(True) 
plt.show() 

Risultato: enter image description here