Scikit-learn: Как запустить KMeans на одномерном массиве?

У меня есть массив из 13.876 (13,876) значений от 0 до 1. Я хотел бы применить sklearn.cluster.KMeans только к этому вектору, чтобы найти разные кластеры, в которых значения сгруппированы. Однако, похоже, KMeans работает с многомерным массивом, а не с одномерными. Я думаю, есть трюк, чтобы заставить его работать, но я не знаю, как это сделать. Я видел, что KMeans.fit() принимает "X: массивную или разреженную матрицу, shape = (n_samples, n_features)", но она хочет, чтобы n_samples быть больше одного

Я попытался поместить свой массив в матрицу np.zeros() и запустить KMeans, но затем помещает все ненулевые значения в класс 1, а остальные - в класс 0.

Может ли кто-нибудь помочь в выполнении этого алгоритма на одномерном массиве? Большое спасибо!

Ответ 1

У вас есть много примеров из 1 функции, поэтому вы можете изменить матрицу на (13,876, 1), используя numpy reshape:

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

Ответ 2

Читайте о Jenks Natural Breaks. Функция в Python обнаружила ссылку из статьи:

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

Использование и визуализация:

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()

Результат: введите здесь описание изображения