Участник:Guryanovak/Алгоритм кластеризации, основанный на минимальном остовном дереве

Материал из Алговики
Перейти к навигации Перейти к поиску

Основные авторы описания: Гурьянов Алексей Константинович, Кибитова Валерия Николаевна

Свойства и структура алгоритмов

Общее описание алгоритма

Математическое описание алгоритма

На вход алгоритму подается набор [math]\displaystyle{ N }[/math] векторов размерности [math]\displaystyle{ m }[/math] : [math]\displaystyle{ (a_{i,1}, a_{i,2}, ..., a_{i,m}) }[/math], где [math]\displaystyle{ a_j \in \mathbb {R} \quad \forall j \in [1,m], i \in [1..N] }[/math] и количество кластеров [math]\displaystyle{ K }[/math], на которые необходимо разбить множество точек.

На выход алгоритм должен вывести [math]\displaystyle{ N }[/math] чисел от [math]\displaystyle{ 1 }[/math] до [math]\displaystyle{ K }[/math], показывающих принадлежность входных векторов кластерам.

Основные обозначения

  • [math]\displaystyle{ E }[/math] - множество рёбер.
  • [math]\displaystyle{ V }[/math] - множество вершин.
  • [math]\displaystyle{ G = (V,E) }[/math] - неориентированный граф, заданный множеством вершин [math]\displaystyle{ V }[/math] и множеством рёбер [math]\displaystyle{ E }[/math]
  • [math]\displaystyle{ MST(G) }[/math] (Minimum Spanning Tree) - минимальное остовное дерево графа [math]\displaystyle{ }[/math]. Остовное дерево — ациклический связный подграф данного связного неориентированного графа, в который входят все его вершины. Минимальное остовное дерево в связанном взвешенном неориентированном графе — это остовное дерево этого графа, имеющее минимальный возможный вес, где под весом дерева понимается сумма весов входящих в него рёбер.

Функция веса

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

В данной статье будет рассматриваться евклидова метрика:

  • [math]\displaystyle{ | x , y | = \sqrt{\sum_i^m (x_i - y_i)^2} }[/math]

Вычислительное ядро алгоритма

Основную часть работы алгоритма занимают два блока:

  • Вычисление расстояний между точками пространства
  • Реализация алгоритма Борувки

Макроструктура алгоритма

В алгоритме используются следующие структуры данных:

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

Для описания алгоритма вводятся следующие макрооперации:

  • 1: getDistance - находит расстояние между двумя вершинами графа как расстояние между соответствующими им точками пространства. (Сложность - O(m))
  • 2: initializeComponents - инициализирует состояние класса Components информацией о вершинах и ребрах. В каждую исходную компоненту связности входит одна вершина. (Сложность - (O(N^2))
  • 3: findMinimalOutgoingEdge - находит ребро c наименьшей длиной, исходящее из заданной компоненты связности. (Cложность - O(N))
  • 4: findComp - возвращает индекс компоненты связности в которой находится вершина (Cложность - O(1))
  • 5: connectComponentsWithEdge - соединяет две компоненты связности, связанные поданным на вход ребром. Объединение компонент включает в себя замену ребер инцидентности новой компоненты на минимальные ребра из пары объединяемых компонент. (Сложность - O(N))

Макрооперации 2-5 относятся к последовательной реализации алгоритма Борувки, который был выбран как основа вычислительного ядра алгоритма.

Схема реализации последовательного алгоритма

int N;        // Размер входных данных
int number_of_clusters;        // Число кластеров
int size = N*N;        // Размер матрицы инцидентности
Node nodes[N];        // Вершины(точки), заданные начальными условиями
Edge edges[size];        // Все расстояния между вершинами 
vector<Edge> tree;        // Рёбра минимального остовного дерева
Components comps;         // Структура компонент связности
read_data(&nodes, file_name);    // Считывание начальных данных

//----------------Вычисление расстояний между вершинами----------------//
for(int i = 0; i < N-1; i++) {
    for(int j = i+1; j < N; j++) {
        double distance = getDistance(node[i], node[j]);        // Вычисление расстояний между вершинами
	edges[i*N + j] = Edge(i,j,distance);        // Запись значения расстояния в массив
        edges[j*N + i] = Edge(i,j,distance);        // Запись значения расстояния в массив
    }
}

//----------------Заполнение данных о компонентах связности--------------//

initializeComponents(&comps, nodes, edges); 

//----------------Построение минимального основного дерева--------------//
while(comps.size > 1) {
    with random component in comps {
        edge e = findMinimalOutgoingEdge(component, comps, edges) // Нахождение минимального ребра инцидентного данной компоненте
        if (findComp(comps, e.first) != findComp(comps, e.second)) { 
             connectComponentsWithEdge(comps, e) // Объединение двух компонент
             tree.add(e) // Добавление ребра в минимальное основное дерево
        }
    } 
}

//-----------------------Разделение на K кластеров--------------------------//
sort(tree)
for(int i = tree.size() - 1; i > tree.size() - 1 - number_of_clusters; i--) {
    remove_edge(tree, i);        // Удаление самых длинных рёбер из MST - формирование кластеров
}
write_data(tree);        // Запись выходных данных

Последовательная сложность алгоритма

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

[math]\displaystyle{ TC(n) = O(N^2m) + O(N^2) + O(N^2) + O(N \log_2 N) = O(N^2m) }[/math]

Информационный граф

Ресурс параллелизма алгоритма

Входные и выходные данные алгоритма

Свойства алгоритма

Программная реализация алгоритма

Особенности реализации последовательного алгоритма

Локальность данных и вычислений

Возможные способы и особенности параллельной реализации алгоритма

Масштабируемость алгоритма и его реализации

Динамические характеристики и эффективность реализации алгоритма

Выводы для классов архитектур

Существующие реализации алгоритма