Как бы вы сгруппировали / сгруппировали эти три области в массивах в python? - PullRequest
16 голосов
/ 20 января 2012

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

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. Обратите внимание, что то, что является большим, а что является маленьким, изменяется, норазница между кластерами остается значительной по сравнению с разницей между элементами группы / кластера.

Ответы [ 5 ]

15 голосов
/ 20 января 2012

Обратите внимание, что ваши точки данных на самом деле одномерны, если x просто представляет индекс.Вы можете кластеризовать свои очки, используя модуль cluster.vq Scipy, который реализует алгоритм 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 .

15 голосов
/ 20 января 2012

Это простой алгоритм, реализованный в python, который проверяет, является ли значение слишком далеко (в терминах стандартного отклонения) от среднего значения кластераЭто вернет то, что вы ожидаете в вашем примере с 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]
6 голосов
/ 20 января 2012

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

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

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

В коде 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 для соответствия распределений вашим данным.

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

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

6 голосов
/ 20 января 2012

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

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

 deltas = diff( sorted(input) )

Затем вы можете разместить свои отсечки там, где вы обнаружите самые большие отличия N-2.

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

0 голосов
/ 20 января 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...