Подтвердить что ты не робот

Как бы вы группировали/группировали эти три области в массивах в python?

Итак, у вас есть массив

1
2
3
60
70
80
100
220
230
250

Для лучшего понимания:

For better understanding

Как бы вы группировали/группировали три области в массивах в python (v2.6), поэтому вы получаете три массива в этом случае, содержащие

[1 2 3] [60 70 80 100] [220 230 250]

Фон:

ось y - частота, ось x - число. Эти цифры представляют собой десять наивысших амплитуд, представленных их частотами. Я хочу создать из них три дискретных числа для распознавания образов. Могло быть много больше очков, но все они сгруппированы относительно большой разницей частот, как вы можете видеть в этом примере от около 50 до около 0 и от около 100 до около 220. Обратите внимание, что большая и небольшие изменения, но разница между кластерами остается значительной по сравнению с разницей между элементами группы/кластера.

4b9b3361

Ответ 1

Это простой алгоритм, реализованный в python, который проверяет, слишком ли (из стандартного отклонения) значение из среднего значения кластера:

from math import sqrt

def stat(lst):
    """Calculate mean and std deviation from the input list."""
    n = float(len(lst))
    mean = sum(lst) / n
    stdev = sqrt((sum(x*x for x in lst) / n) - (mean * mean)) 
    return mean, stdev

def parse(lst, n):
    cluster = []
    for i in lst:
        if len(cluster) <= 1:    # the first two values are going directly in
            cluster.append(i)
            continue

        mean,stdev = stat(cluster)
        if abs(mean - i) > n * stdev:    # check the "distance"
            yield cluster
            cluster[:] = []    # reset cluster to the empty list

        cluster.append(i)
    yield cluster           # yield the last cluster

Это вернет то, что вы ожидаете в своем примере с помощью 5 < n < 9:

>>> array = [1, 2, 3, 60, 70, 80, 100, 220, 230, 250]
>>> for cluster in parse(array, 7):
...     print(cluster)
[1, 2, 3]
[60, 70, 80, 100]
[220, 230, 250]

Ответ 2

Обратите внимание, что ваши точки данных на самом деле одномерны, если x просто представляет индекс. Вы можете сгруппировать свои точки с помощью модуля Scipy cluster.vq, который реализует алгоритм k-средних.

>>> import numpy as np
>>> from scipy.cluster.vq import kmeans, vq
>>> y = np.array([1,2,3,60,70,80,100,220,230,250])
>>> codebook, _ = kmeans(y, 3)  # three clusters
>>> cluster_indices, _ = vq(y, codebook)
>>> cluster_indices
array([1, 1, 1, 0, 0, 0, 0, 2, 2, 2])

Результат: первые три точки образуют кластер 1 (произвольная метка), следующий четыре кластера форм 0 и последние три кластера форм 2. Группировка исходных точек в соответствии с индексами оставлена ​​в качестве упражнения для читателя.

Для большего количества алгоритмов кластеризации в Python проверьте scikit-learn.

Ответ 3

Я предполагаю, что вам нужен довольно хороший, но простой алгоритм.

Если вы знаете, что хотите N кластеров, то вы можете принимать различия (дельта) между последовательными членами (отсортированного) списка входных данных. Например. в numpy:

 deltas = diff( sorted(input) )

Затем вы можете поместить свои cuttffs, где вы найдете N-2 самых больших различий.

Делают сложнее, если вы не знаете, что такое N. Здесь вы можете поместить cuttoffs, когда увидите дельту больше определенного размера. Тогда это будет настраиваемый вручную параметр, который невелик, но может быть достаточно для вас.

Ответ 4

Вы можете решить это различными способами. Одним из очевидных, когда вы бросаете ключевое слово "кластеризация", является использование kmeans (см. Другие ответы).

Однако вы можете сначала понять, что вы на самом деле делаете или пытаетесь сделать. Вместо того, чтобы просто бросать случайную функцию на ваши данные.

Насколько я могу судить по вашему вопросу, у вас есть несколько одномерных значений, и вы хотите разделить их на неизвестное количество групп, не так ли? Ну, k-средства могут сделать трюк, но на самом деле вы можете просто искать k самых больших различий в вашем наборе данных. То есть для любого индекса i > 0, вычислите k[i] - k[i-1] и выберите индексы k, где это больше, чем для остальных. Скорее всего, ваш результат будет лучше и быстрее, чем использование k -средств.

В коде python:

k = 2
a = [1, 2, 3, 60, 70, 80, 100, 220, 230, 250]
a.sort()
b=[] # A *heap* would be faster
for i in range(1, len(a)):
  b.append( (a[i]-a[i-1], i) )
b.sort()
# b now is [... (20, 6), (20, 9), (57, 3), (120, 7)]
# and the last ones are the best split points.
b = map(lambda p: p[1], b[-k:])
b.sort()
# b now is: [3, 7]
b.insert(0, 0)
b.append(len(a) + 1)
for i in range(1, len(b)):
  print a[b[i-1]:b[i]],
# Prints [1, 2, 3] [60, 70, 80, 100] [220, 230, 250]

(Это может быть рассмотрено как простая одноканальная кластеризация!)

Более продвинутый метод, который фактически избавляется от параметра k, вычисляет среднее и стандартное отклонение b[*][1] и расщепляется, если значение больше, чем говорят mean+2*stddev. Тем не менее это довольно грубая эвристика. Другим вариантом было бы фактически принять распределение значений, такое как k нормальные распределения, а затем использовать, например, Levenberg-Marquardt, чтобы соответствовать распределениям ваших данных.

Но действительно ли это то, что вы хотите сделать?

Сначала попробуйте определить, какой должен быть кластер, а что нет. Вторая часть гораздо важнее.

Ответ 5

Вы можете использовать кластер ближайших соседей. Чтобы точка принадлежала одному из кластеров, ее ближайший сосед также должен принадлежать кластеру. В случае, которое вы показали, вам просто нужно пройти по оси х и сравнить различия с соседними точками. Когда разница с предыдущей точкой больше, чем разница с следующей точкой, это указывает на начало нового кластера.