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

enter image description here

По моим данным, круги представлены координатами их центральной точки. Я уже сделал обнаружение столкновений, чтобы получить список парных центрированных точек, представляющих перекрытия:

pts = [(-2,2), (-2,2), (0,0), (2,1), (6,2), (7,1)]

overlaps = [
    (pts[0], pts[1]),
    (pts[0], pts[2]),
    (pts[1], pts[2]),
    (pts[2], pts[3]),
    (pts[4], pts[5]),
]

Это ожидаемый результат:

expected_clusters = [
    ((-2,2), (-2,2), (0,0), (2,1)),
    ((6,2), (7,1))
]

На практике наборы данных, с которыми я буду работать, будут примерно такого размера, поэтому мне, вероятно, никогда не понадобится увеличивать их. Но это не значит, что я не предпочел бы более оптимальное решение.

Я придумала собственное наивное решение, которое я опубликую в качестве ответа. Но мне было бы интересно увидеть другие решения.

2
klenwell 30 Янв 2013 в 19:16

2 ответа

Лучший ответ

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

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

  1. Создайте список L всех узлов.
  2. Создать пустой список подключенных компонентов Cs
  3. Пока L не пуст: < Ол >
  4. Выберите произвольный узел N
  5. Создайте список подключенных компонентов C, инициализированный N
  6. Выполните обход в ширину или вглубь, используя список смежности, добавив каждый встреченный узел в C
  7. Добавить C в Cs
  8. Удалить все узлы в C из L
5
acjay 30 Янв 2013 в 15:45

Отредактировал исходный ответ в пользу алгоритма acjohnson55:

center_pts = [(-2,2), (-2,2), (0,0), (2,1), (6,2), (7,1)]

overlapping_circle_pts = [
    (center_pts[0], center_pts[1]),
    (center_pts[0], center_pts[2]),
    (center_pts[1], center_pts[2]),
    (center_pts[2], center_pts[3]),
    (center_pts[4], center_pts[5]),
]

expected_solution = [
    [(-2,2), (-2,2), (0,0), (2,1)],
    [(6,2), (7,1)]
]


def cluster_overlaps(nodes, adjacency_list):
    clusters = []
    nodes = list(nodes)  # make sure we're mutating a copy

    while len(nodes):
        node = nodes[0]
        path = dfs(node, adjacency_list, nodes)

        # append path to connected_nodes
        clusters.append(path)

        # remove all nodes from
        for pt in path:
            nodes.remove(pt)

    return clusters


def dfs(start, adjacency_list, nodes):
    """ref: http://code.activestate.com/recipes/576723/"""
    path = []
    q = [start]

    while q:
        node = q.pop(0)

        # cycle detection
        if path.count(node) >= nodes.count(node):
            continue

        path = path + [node]

        # get next nodes
        next_nodes = [p2 for p1,p2 in adjacency_list if p1 == node]
        q = next_nodes + q

    return path

print cluster_overlaps(center_pts, overlapping_circle_pts)
1
Community 23 Май 2017 в 12:14