<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Lkruglov</id>
	<title>Алговики - Вклад [ru]</title>
	<link rel="self" type="application/atom+xml" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Lkruglov"/>
	<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/ru/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/Lkruglov"/>
	<updated>2026-10-22T17:17:46Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=21477</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=21477"/>
		<updated>2016-12-21T02:52:11Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Как показано на информационном графе, значительная часть алгоритма не предполагает параллельного выполнения. Взаимной независимостью обладают только фрагмент, где создаются локальные кучи, и ряд действий по перемещению точек между кучами.&lt;br /&gt;
&lt;br /&gt;
Для оценки производительности была выбрана реализация из [https://github.com/annoviko/pyclustering pyclustering], выполненная на C++. Для тестирования использовался суперкомпьютер «Ломоносов» [6] [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Из всех методов, задействованных в реализации, возможности для параллельного выполнения включали два, &#039;&#039;calculate_links&#039;&#039; и &#039;&#039;create_adjacency_matrix&#039;&#039;. В обоих случаях были предприняты попытки использования этих возможностей.&lt;br /&gt;
&lt;br /&gt;
Метод &#039;&#039;calculate_links&#039;&#039; в оригинальной версии отвечал за 20-25% общего времени выполнения. После распараллеливания на OpenMP производительность только ухудшилась. Для наглядности исходный код метода приведен ниже:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
size_t rock::calculate_links(const cluster &amp;amp; cluster1, const cluster &amp;amp; cluster2) const {&lt;br /&gt;
    size_t number_links = 0;&lt;br /&gt;
    #pragma omp parallel for reduction(+:number_links)&lt;br /&gt;
    for (size_t ii = 0; ii &amp;lt; cluster1.size(); ++ii) {&lt;br /&gt;
        for (size_t jj = 0; jj &amp;lt; cluster2.size(); ++jj) {&lt;br /&gt;
            std::size_t i = cluster1[ii];&lt;br /&gt;
            std::size_t j = cluster2[jj];&lt;br /&gt;
            number_links += (size_t) m_adjacency_matrix.has_connection(i, j);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как видно, проблема заключается в том, что метод практически не содержит вычислений, и его производительность определяется в первую очередь производительностью памяти. Таким образом, OpenMP просто распределил время ожидания доступа к памяти между различными процессами.&lt;br /&gt;
&lt;br /&gt;
Метод &#039;&#039;create_adjacency_matrix&#039;&#039; также был распараллелен с помощью MPI. К качественному ускорению это не привело в первую очередь из-за того, что на использованных тестах среднее время выполнения этого метода занимало около 0.004% от общего времени выполнения. Распараллеленный код приведен ниже для справки.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
void rock::create_adjacency_matrix(const dataset &amp;amp; p_data) {&lt;br /&gt;
    m_adjacency_matrix = adjacency_matrix(p_data.size());&lt;br /&gt;
&lt;br /&gt;
    int procNum = 0;&lt;br /&gt;
    MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;procNum);&lt;br /&gt;
&lt;br /&gt;
    const size_t mSize = m_adjacency_matrix.size();&lt;br /&gt;
    const size_t q = mSize / procNum;&lt;br /&gt;
    const size_t blockSize = (mSize % procNum == 0) ? q : (q + 1);&lt;br /&gt;
&lt;br /&gt;
    MPI_Request reqs[mSize];&lt;br /&gt;
    MPI_Request sendReqs[blockSize];&lt;br /&gt;
    MPI_Status stats[mSize];&lt;br /&gt;
&lt;br /&gt;
    if (m_rank == 0) {&lt;br /&gt;
        for (size_t i = 0; i &amp;lt; blockSize; ++i) {&lt;br /&gt;
            reqs[i] = MPI_REQUEST_NULL;&lt;br /&gt;
        }&lt;br /&gt;
        for (size_t r = 1; r &amp;lt; procNum; ++r) {&lt;br /&gt;
            for (size_t i = r * blockSize; i &amp;lt; (r + 1) * blockSize &amp;amp;&amp;amp; i &amp;lt; mSize; ++i) {&lt;br /&gt;
                MPI_Irecv(&amp;amp;(m_adjacency_matrix.raw_data()[i][0]), mSize, MPI_DOUBLE, r, 0, MPI_COMM_WORLD, reqs + i);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (size_t i = m_rank * blockSize; i &amp;lt; (m_rank + 1) * blockSize &amp;amp;&amp;amp; i &amp;lt; mSize; ++i) {&lt;br /&gt;
        for (size_t j = i + 1; j &amp;lt; mSize; j++) {&lt;br /&gt;
            double distance = euclidean_distance_sqrt(&amp;amp;p_data[i], &amp;amp;p_data[j]);&lt;br /&gt;
            if (distance &amp;lt; m_radius) {&lt;br /&gt;
                m_adjacency_matrix.set_connection(i, j);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (m_rank == 0) {&lt;br /&gt;
        MPI_Waitall(mSize, reqs, stats);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        size_t j = 0;&lt;br /&gt;
        for (size_t i = m_rank * blockSize; i &amp;lt; (m_rank + 1) * blockSize &amp;amp;&amp;amp; i &amp;lt; mSize; ++i, ++j) {&lt;br /&gt;
            MPI_Isend(&amp;amp;(m_adjacency_matrix.raw_data()[i][0]), mSize, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, sendReqs + j);&lt;br /&gt;
        }&lt;br /&gt;
        for (; j &amp;lt; blockSize; ++j) {&lt;br /&gt;
            sendReqs[j] = MPI_REQUEST_NULL;&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Waitall(blockSize, sendReqs, stats);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO: 2 графика&lt;br /&gt;
&lt;br /&gt;
Таким образом, попытки распараллеливания данной реализации алгоритма не привели к уменьшению времени ее работы, что согласуется с оценками параллельного ресурса самого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;br /&gt;
&lt;br /&gt;
[6] Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=21476</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=21476"/>
		<updated>2016-12-21T02:43:36Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Как показано на информационном графе, значительная часть алгоритма не предполагает параллельного выполнения. Взаимной независимостью обладают только фрагмент, где создаются локальные кучи, и ряд действий по перемещению точек между кучами.&lt;br /&gt;
&lt;br /&gt;
Для оценки производительности была выбрана реализация из [https://github.com/annoviko/pyclustering pyclustering], выполненная на C++. Исходная версия алгоритма показала следующие результаты. Здесь и далее для тестирования использовался суперкомпьютер «Ломоносов» [6] [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Название теста&lt;br /&gt;
! Время выполнения (сек)&lt;br /&gt;
! Количество точек&lt;br /&gt;
! Количество кластеров&lt;br /&gt;
|-&lt;br /&gt;
| Chainlink&lt;br /&gt;
| 312.7&lt;br /&gt;
| 1500&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| TwoDiamonds&lt;br /&gt;
| 160.4&lt;br /&gt;
| 1270&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| Target&lt;br /&gt;
| 142.9&lt;br /&gt;
| 1150&lt;br /&gt;
| 6&lt;br /&gt;
|-&lt;br /&gt;
| WingNut&lt;br /&gt;
| 1324.6&lt;br /&gt;
| 2400&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| EngyTime&lt;br /&gt;
| 2728.09&lt;br /&gt;
| 4096&lt;br /&gt;
| 13&lt;br /&gt;
|-&lt;br /&gt;
| GolfBall&lt;br /&gt;
| 2429.69&lt;br /&gt;
| 4002&lt;br /&gt;
| 13&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Из всех методов, задействованных в реализации, возможности для параллельного выполнения включали два, &#039;&#039;calculate_links&#039;&#039; и &#039;&#039;create_adjacency_matrix&#039;&#039;. В обоих случаях были предприняты попытки использования этих возможностей.&lt;br /&gt;
&lt;br /&gt;
Метод &#039;&#039;calculate_links&#039;&#039; в оригинальной версии отвечал за 20-25% общего времени выполнения. После распараллеливания на OpenMP производительность только ухудшилась, тот же результат принесло использование MPI. Для наглядности исходный код метода приведен ниже:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
size_t rock::calculate_links(const cluster &amp;amp; cluster1, const cluster &amp;amp; cluster2) const {&lt;br /&gt;
    size_t number_links = 0;&lt;br /&gt;
    #pragma omp parallel for reduction(+:number_links)&lt;br /&gt;
    for (size_t ii = 0; ii &amp;lt; cluster1.size(); ++ii) {&lt;br /&gt;
        for (size_t jj = 0; jj &amp;lt; cluster2.size(); ++jj) {&lt;br /&gt;
            std::size_t i = cluster1[ii];&lt;br /&gt;
            std::size_t j = cluster2[jj];&lt;br /&gt;
            number_links += (size_t) m_adjacency_matrix.has_connection(i, j);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как видно, проблема заключается в том, что метод практически не содержит вычислений, и его производительность определяется в первую очередь производительностью памяти. Таким образом, OpenMP просто распределил время ожидания доступа к памяти между различными процессами, а MPI добавил времени за счет выполнения передач между узлами.&lt;br /&gt;
&lt;br /&gt;
Метод &#039;&#039;create_adjacency_matrix&#039;&#039; также был распараллелен с помощью MPI. К качественному ускорению это не привело в первую очередь из-за того, что на использованных тестах среднее время выполнения этого метода занимало около 0.004% от общего времени выполнения. Распараллеленный код приведен ниже для справки.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
void rock::create_adjacency_matrix(const dataset &amp;amp; p_data) {&lt;br /&gt;
    m_adjacency_matrix = adjacency_matrix(p_data.size());&lt;br /&gt;
&lt;br /&gt;
    int procNum = 0;&lt;br /&gt;
    MPI_Comm_size(MPI_COMM_WORLD, &amp;amp;procNum);&lt;br /&gt;
&lt;br /&gt;
    const size_t mSize = m_adjacency_matrix.size();&lt;br /&gt;
    const size_t q = mSize / procNum;&lt;br /&gt;
    const size_t blockSize = (mSize % procNum == 0) ? q : (q + 1);&lt;br /&gt;
&lt;br /&gt;
    MPI_Request reqs[mSize];&lt;br /&gt;
    MPI_Request sendReqs[blockSize];&lt;br /&gt;
    MPI_Status stats[mSize];&lt;br /&gt;
&lt;br /&gt;
    if (m_rank == 0) {&lt;br /&gt;
        for (size_t i = 0; i &amp;lt; blockSize; ++i) {&lt;br /&gt;
            reqs[i] = MPI_REQUEST_NULL;&lt;br /&gt;
        }&lt;br /&gt;
        for (size_t r = 1; r &amp;lt; procNum; ++r) {&lt;br /&gt;
            for (size_t i = r * blockSize; i &amp;lt; (r + 1) * blockSize &amp;amp;&amp;amp; i &amp;lt; mSize; ++i) {&lt;br /&gt;
                MPI_Irecv(&amp;amp;(m_adjacency_matrix.raw_data()[i][0]), mSize, MPI_DOUBLE, r, 0, MPI_COMM_WORLD, reqs + i);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (size_t i = m_rank * blockSize; i &amp;lt; (m_rank + 1) * blockSize &amp;amp;&amp;amp; i &amp;lt; mSize; ++i) {&lt;br /&gt;
        for (size_t j = i + 1; j &amp;lt; mSize; j++) {&lt;br /&gt;
            double distance = euclidean_distance_sqrt(&amp;amp;p_data[i], &amp;amp;p_data[j]);&lt;br /&gt;
            if (distance &amp;lt; m_radius) {&lt;br /&gt;
                m_adjacency_matrix.set_connection(i, j);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (m_rank == 0) {&lt;br /&gt;
        MPI_Waitall(mSize, reqs, stats);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        size_t j = 0;&lt;br /&gt;
        for (size_t i = m_rank * blockSize; i &amp;lt; (m_rank + 1) * blockSize &amp;amp;&amp;amp; i &amp;lt; mSize; ++i, ++j) {&lt;br /&gt;
            MPI_Isend(&amp;amp;(m_adjacency_matrix.raw_data()[i][0]), mSize, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, sendReqs + j);&lt;br /&gt;
        }&lt;br /&gt;
        for (; j &amp;lt; blockSize; ++j) {&lt;br /&gt;
            sendReqs[j] = MPI_REQUEST_NULL;&lt;br /&gt;
        }&lt;br /&gt;
        MPI_Waitall(blockSize, sendReqs, stats);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, попытки распараллеливания данной реализации алгоритма не привели к уменьшению времени ее работы, что согласуется с оценками параллельного ресурса самого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;br /&gt;
&lt;br /&gt;
[6] Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=18255</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=18255"/>
		<updated>2016-11-18T19:10:12Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{Assignment|Teplov}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Как показано на информационном графе, значительная часть алгоритма не предполагает параллельного выполнения. Взаимной независимостью обладают только фрагмент, где создаются локальные кучи, и ряд действий по перемещению точек между кучами.&lt;br /&gt;
&lt;br /&gt;
Для оценки производительности была выбрана реализация из [https://github.com/annoviko/pyclustering pyclustering], выполненная на C++. Исходная версия алгоритма показала следующие результаты. Здесь и далее для тестирования использовался суперкомпьютер «Ломоносов» [6] [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Название теста&lt;br /&gt;
! Время выполнения (сек)&lt;br /&gt;
! Количество точек&lt;br /&gt;
! Количество кластеров&lt;br /&gt;
|-&lt;br /&gt;
| Chainlink&lt;br /&gt;
| 312.7&lt;br /&gt;
| 1500&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| TwoDiamonds&lt;br /&gt;
| 160.4&lt;br /&gt;
| 1270&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| Target&lt;br /&gt;
| 142.9&lt;br /&gt;
| 1150&lt;br /&gt;
| 6&lt;br /&gt;
|-&lt;br /&gt;
| WingNut&lt;br /&gt;
| 1324.6&lt;br /&gt;
| 2400&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| EngyTime&lt;br /&gt;
| 2728.09&lt;br /&gt;
| 4096&lt;br /&gt;
| 13&lt;br /&gt;
|-&lt;br /&gt;
| GolfBall&lt;br /&gt;
| 2429.69&lt;br /&gt;
| 4002&lt;br /&gt;
| 13&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Из всех методов, задействованных в реализации, возможности для параллельного выполнения включали два, &#039;&#039;calculate_links&#039;&#039; и &#039;&#039;create_adjacency_matrix&#039;&#039;. В обоих случаях были предприняты попытки использования этих возможностей.&lt;br /&gt;
&lt;br /&gt;
Метод &#039;&#039;calculate_links&#039;&#039; в оригинальной версии отвечал за 20-25% общего времени выполнения. После распараллеливания на OpenMP производительность только ухудшилась, тот же результат принесло использование MPI. Для наглядности исходный код метода приведен ниже:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
size_t rock::calculate_links(const cluster &amp;amp; cluster1, const cluster &amp;amp; cluster2) const {&lt;br /&gt;
    size_t number_links = 0;&lt;br /&gt;
    for (auto i : cluster1)&lt;br /&gt;
        for (auto j : cluster2)&lt;br /&gt;
            number_links += (size_t) m_adjacency_matrix.has_connection(i, j);&lt;br /&gt;
    return number_links;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как видно, проблема заключается в том, что метод практически не содержит вычислений, и его производительность определяется в первую очередь производительностью памяти. Таким образом, OpenMP просто распределил время ожидания доступа к памяти между различными процессами, а MPI добавил времени за счет выполнения передач между узлами.&lt;br /&gt;
&lt;br /&gt;
Метод &#039;&#039;create_adjacency_matrix&#039;&#039; также был распараллелен с помощью MPI. К качественному ускорению это не привело в первую очередь из-за того, что на использованных тестах среднее время выполнения этого метода занимало около 0.004% от общего времени выполнения.&lt;br /&gt;
&lt;br /&gt;
Таким образом, попытки распараллеливания данной реализации алгоритма не привели к уменьшению времени ее работы, что согласуется с оценками параллельного ресурса самого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;br /&gt;
&lt;br /&gt;
[6] Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=18250</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=18250"/>
		<updated>2016-11-18T19:05:24Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{Assignment|Teplov}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Как показано на информационном графе, значительная часть алгоритма не предполагает параллельного выполнения. Взаимной независимостью обладают только фрагмент, где создаются локальные кучи, и ряд действий по перемещению точек между кучами.&lt;br /&gt;
&lt;br /&gt;
Для оценки производительности была выбрана реализация из [https://github.com/annoviko/pyclustering annoviko/pyclustering], выполненная на C++. Исходная версия алгоритма показала следующие результаты. Здесь и далее для тестирования использовался суперкомпьютер «Ломоносов» [6] [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Название теста&lt;br /&gt;
! Время выполнения (сек)&lt;br /&gt;
! Количество точек&lt;br /&gt;
! Количество кластеров&lt;br /&gt;
|-&lt;br /&gt;
| Chainlink&lt;br /&gt;
| 312.7&lt;br /&gt;
| 1500&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| TwoDiamonds&lt;br /&gt;
| 160.4&lt;br /&gt;
| 1270&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| Target&lt;br /&gt;
| 142.9&lt;br /&gt;
| 1150&lt;br /&gt;
| 6&lt;br /&gt;
|-&lt;br /&gt;
| WingNut&lt;br /&gt;
| 1324.6&lt;br /&gt;
| 2400&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| EngyTime&lt;br /&gt;
| 2728.09&lt;br /&gt;
| 4096&lt;br /&gt;
| 13&lt;br /&gt;
|-&lt;br /&gt;
| GolfBall&lt;br /&gt;
| 2429.69&lt;br /&gt;
| 4002&lt;br /&gt;
| 13&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Из всех методов, задействованных в реализации, возможности для параллельного выполнения включали два, calculate_links и create_adjacency_matrix. В обоих случаях были предприняты попытки использования этих возможностей.&lt;br /&gt;
&lt;br /&gt;
Метод calculate_links в оригинальной версии отвечал за 20-25% общего времени выполнения. После распараллеливания на OpenMP производительность только ухудшилась, тот же результат принесло использование MPI. Для наглядности исходный код метода приведен ниже:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
size_t rock::calculate_links(const cluster &amp;amp; cluster1, const cluster &amp;amp; cluster2) const {&lt;br /&gt;
    size_t number_links = 0;&lt;br /&gt;
    for (auto i : cluster1)&lt;br /&gt;
        for (auto j : cluster2)&lt;br /&gt;
            number_links += (size_t) m_adjacency_matrix.has_connection(i, j);&lt;br /&gt;
    return number_links;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как видно, проблема заключается в том, что метод практически не содержит вычислений, и его производительность определяется в первую очередь производительностью памяти. Таким образом, OpenMP просто распределил время ожидания доступа к памяти между различными процессами, а MPI добавил времени за счет выполнения передач между узлами.&lt;br /&gt;
&lt;br /&gt;
Метод create_adjacency_matrix также был распараллелен с помощью MPI. К качественному ускорению это не привело в первую очередь из-за того, что на использованных тестах среднее время выполнения этого метода занимало около 0.004% от общего времени выполнения.&lt;br /&gt;
&lt;br /&gt;
Таким образом, попытки распараллеливания данной реализации алгоритма не привели к уменьшению времени ее работы, что согласуется с оценками параллельного ресурса самого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;br /&gt;
&lt;br /&gt;
[6] Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=18247</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=18247"/>
		<updated>2016-11-18T19:04:16Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{Assignment|Teplov}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Как показано на информационном графе, значительная часть алгоритма не предполагает параллельного выполнения. Взаимной независимостью обладают только фрагмент, где создаются локальные кучи, и ряд действий по перемещению точек между кучами.&lt;br /&gt;
&lt;br /&gt;
Для оценки производительности была выбрана реализация из [https://github.com/annoviko/pyclustering annoviko/pyclustering], выполненная на C++. Исходная версия алгоритма показала следующие результаты. Здесь и далее для тестирования использовался суперкомпьютер «Ломоносов» [6] [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Название теста&lt;br /&gt;
! Время выполнения (сек)&lt;br /&gt;
! Количество точек&lt;br /&gt;
! Количество кластеров&lt;br /&gt;
|-&lt;br /&gt;
| Chainlink&lt;br /&gt;
| 312.7&lt;br /&gt;
| 1500&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| TwoDiamonds&lt;br /&gt;
| 160.4&lt;br /&gt;
| 1270&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| Target&lt;br /&gt;
| 142.9&lt;br /&gt;
| 1150&lt;br /&gt;
| 6&lt;br /&gt;
|-&lt;br /&gt;
| WingNut&lt;br /&gt;
| 1324.6&lt;br /&gt;
| 2400&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| EngyTime&lt;br /&gt;
| 2728.09&lt;br /&gt;
| 4096&lt;br /&gt;
| 13&lt;br /&gt;
|-&lt;br /&gt;
| GolfBall&lt;br /&gt;
| 2429.69&lt;br /&gt;
| 4002&lt;br /&gt;
| 13&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Из всех методов, задействованных в реализации, возможности для параллельного выполнения включали два, calculate_links и create_adjacency_matrix. В обоих случаях были предприняты попытки использования этих возможностей.&lt;br /&gt;
&lt;br /&gt;
Метод calculate_links в оригинальной версии отвечал за 20-25% общего времени выполнения. После распараллеливания на OpenMP производительность только ухудшилась, тот же результат принесло использование MPI. Для наглядности исходный код метода приведен ниже.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
size_t rock::calculate_links(const cluster &amp;amp; cluster1, const cluster &amp;amp; cluster2) const {&lt;br /&gt;
    size_t number_links = 0;&lt;br /&gt;
    for (auto i : cluster1)&lt;br /&gt;
        for (auto j : cluster2)&lt;br /&gt;
            number_links += (size_t) m_adjacency_matrix.has_connection(i, j);&lt;br /&gt;
    return number_links;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как видно, проблема заключается в том, что метод практически не содержит вычислений, и его производительность определяется в первую очередь производительностью памяти. Таким образом, OpenMP просто распределил время ожидания доступа к памяти между различными процессами, а MPI добавил времени за счет выполнения передач между узлами.&lt;br /&gt;
&lt;br /&gt;
Метод create_adjacency_matrix также был распараллелен с помощью MPI. К качественному ускорению это не привело в первую очередь из-за того, что на использованных тестах среднее время выполнения этого метода занимало около 0.004% от общего времени выполнения.&lt;br /&gt;
&lt;br /&gt;
Таким образом, попытки распараллеливания данной реализации алгоритма не привели к уменьшению времени ее работы, что согласуется с оценками параллельного ресурса самого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;br /&gt;
&lt;br /&gt;
[6] Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=17251</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=17251"/>
		<updated>2016-11-15T13:22:26Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{Assignment|Teplov}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Как показано на информационном графе, значительная часть алгоритма не предполагает параллельного выполнения. Взаимной независимостью обладают только фрагмент, где создаются локальные кучи, и ряд действий по перемещению точек между кучами.&lt;br /&gt;
&lt;br /&gt;
Для оценки производительности была выбрана реализация из [https://github.com/annoviko/pyclustering annoviko/pyclustering], выполненная на C++. Исходная версия алгоритма показала следующие результаты. Здесь и далее для тестирования использовался суперкомпьютер «Ломоносов» [6] [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Название теста&lt;br /&gt;
! Время выполнения (сек)&lt;br /&gt;
! Количество точек&lt;br /&gt;
! Количество кластеров&lt;br /&gt;
|-&lt;br /&gt;
| Chainlink&lt;br /&gt;
| 312.7&lt;br /&gt;
| 1500&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| TwoDiamonds&lt;br /&gt;
| 160.4&lt;br /&gt;
| 1270&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| Target&lt;br /&gt;
| 142.9&lt;br /&gt;
| 1150&lt;br /&gt;
| 6&lt;br /&gt;
|-&lt;br /&gt;
| WingNut&lt;br /&gt;
| 1324.6&lt;br /&gt;
| 2400&lt;br /&gt;
| 2&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Из всех методов, задействованных в реализации, возможности для параллельного выполнения включали два, calculate_links и create_adjacency_matrix. В обоих случаях были предприняты попытки использования этих возможностей.&lt;br /&gt;
&lt;br /&gt;
Метод calculate_links в оригинальной версии отвечал за 20-25% общего времени выполнения. После распараллеливания на OpenMP производительность только ухудшилась, тот же результат принесло использование MPI. Для наглядности исходный код метода приведен ниже.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
size_t rock::calculate_links(const cluster &amp;amp; cluster1, const cluster &amp;amp; cluster2) const {&lt;br /&gt;
    size_t number_links = 0;&lt;br /&gt;
    for (auto i : cluster1)&lt;br /&gt;
        for (auto j : cluster2)&lt;br /&gt;
            number_links += (size_t) m_adjacency_matrix.has_connection(i, j);&lt;br /&gt;
    return number_links;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как видно, проблема заключается в том, что метод практически не содержит вычислений, и его производительность определяется в первую очередь производительностью памяти. Таким образом, OpenMP просто распределил время ожидания доступа к памяти между различными процессами, а MPI добавил времени за счет выполнения передач между узлами.&lt;br /&gt;
&lt;br /&gt;
Метод create_adjacency_matrix также был распараллелен с помощью MPI. К качественному ускорению это не привело в первую очередь из-за того, что на использованных тестах среднее время выполнения этого метода занимало около 0.004% от общего времени выполнения.&lt;br /&gt;
&lt;br /&gt;
Таким образом, попытки распараллеливания данной реализации алгоритма не привели к уменьшению времени ее работы, что согласуется с оценками параллельного ресурса самого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;br /&gt;
&lt;br /&gt;
[6] Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=17087</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=17087"/>
		<updated>2016-11-14T17:48:17Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Teplov}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Как показано на информационном графе, значительная часть алгоритма не предполагает параллельного выполнения. Взаимной независимостью обладают только фрагмент, где создаются локальные кучи, и ряд действий по перемещению точек между кучами.&lt;br /&gt;
&lt;br /&gt;
Для оценки производительности была выбрана реализация из [https://github.com/annoviko/pyclustering annoviko/pyclustering], выполненная на C++. Исходная версия алгоритма показала следующие результаты. Здесь и далее для тестирования использовался суперкомпьютер «Ломоносов» [6] [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Название теста&lt;br /&gt;
! Время выполнения (сек)&lt;br /&gt;
! Количество точек&lt;br /&gt;
! Количество кластеров&lt;br /&gt;
|-&lt;br /&gt;
| Chainlink&lt;br /&gt;
| 312.7&lt;br /&gt;
| 1500&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| TwoDiamonds&lt;br /&gt;
| 160.4&lt;br /&gt;
| 1270&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| Target&lt;br /&gt;
| 142.9&lt;br /&gt;
| 1150&lt;br /&gt;
| 6&lt;br /&gt;
|-&lt;br /&gt;
| WingNut&lt;br /&gt;
| 1324.6&lt;br /&gt;
| 2400&lt;br /&gt;
| 2&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Из всех методов, задействованных в реализации, возможности для параллельного выполнения включали два, calculate_links и create_adjacency_matrix. В обоих случаях были предприняты попытки использования этих возможностей.&lt;br /&gt;
&lt;br /&gt;
Метод calculate_links в оригинальной версии отвечал за 20-25% общего времени выполнения. После распараллеливания на OpenMP производительность только ухудшилась, тот же результат принесло использование MPI. Для наглядности исходный код метода приведен ниже.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
size_t rock::calculate_links(const cluster &amp;amp; cluster1, const cluster &amp;amp; cluster2) const {&lt;br /&gt;
    size_t number_links = 0;&lt;br /&gt;
    for (auto i : cluster1)&lt;br /&gt;
        for (auto j : cluster2)&lt;br /&gt;
            number_links += (size_t) m_adjacency_matrix.has_connection(i, j);&lt;br /&gt;
    return number_links;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как видно, проблема заключается в том, что метод практически не содержит вычислений, и его производительность определяется в первую очередь производительностью памяти. Таким образом, OpenMP просто распределил время ожидания доступа к памяти между различными процессами, а MPI добавил времени за счет выполнения передач между узлами.&lt;br /&gt;
&lt;br /&gt;
Метод create_adjacency_matrix также был распараллелен с помощью MPI. К качественному ускорению это не привело в первую очередь из-за того, что на использованных тестах среднее время выполнения этого метода занимало около 0.004% от общего времени выполнения.&lt;br /&gt;
&lt;br /&gt;
Таким образом, попытки распараллеливания данной реализации алгоритма не привели к уменьшению времени ее работы, что согласуется с оценками параллельного ресурса самого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;br /&gt;
&lt;br /&gt;
[6] Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=17086</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=17086"/>
		<updated>2016-11-14T17:47:10Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Литература */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Teplov}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Как показано на информационном графе, значительная часть алгоритма не предполагает параллельного выполнения. Взаимной независимостью обладают только фрагмент, где создаются локальные кучи, и ряд действий по перемещению точек между кучами.&lt;br /&gt;
&lt;br /&gt;
Для оценки производительности была выбрана реализация из [https://github.com/annoviko/pyclustering annoviko/pyclustering], выполненная на C++. Исходная версия алгоритма показала следующие результаты. Здесь и далее для тестирования использовался суперкомпьютер «Ломоносов» [6] [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Название теста&lt;br /&gt;
! Время выполнения (сек)&lt;br /&gt;
! Количество точек&lt;br /&gt;
! Количество кластеров&lt;br /&gt;
|-&lt;br /&gt;
| Chainlink&lt;br /&gt;
| 312.7&lt;br /&gt;
| 1500&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| TwoDiamonds&lt;br /&gt;
| 160.4&lt;br /&gt;
| 1270&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| Target&lt;br /&gt;
| 142.9&lt;br /&gt;
| 1150&lt;br /&gt;
| 6&lt;br /&gt;
|-&lt;br /&gt;
| WingNut&lt;br /&gt;
| 1324.6&lt;br /&gt;
| 2400&lt;br /&gt;
| 2&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Из всех методов, задействованных в реализации, возможности для параллельного выполнения включали два, calculate_links и create_adjacency_matrix. В обоих случаях были предприняты попытки использования этих возможностей.&lt;br /&gt;
&lt;br /&gt;
Метод calculate_links в оригинальной версии отвечал за 20-25% общего времени выполнения. После распараллеливания на OpenMP производительность только ухудшилась, тот же результат принесло использование MPI. Для наглядности исходный код метода приведен ниже.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
size_t rock::calculate_links(const cluster &amp;amp; cluster1, const cluster &amp;amp; cluster2) const {&lt;br /&gt;
    size_t number_links = 0;&lt;br /&gt;
    for (auto i : cluster1)&lt;br /&gt;
        for (auto j : cluster2)&lt;br /&gt;
            number_links += (size_t) m_adjacency_matrix.has_connection(i, j);&lt;br /&gt;
    return number_links;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как видно, проблема заключается в том, что метод практически не содержит вычислений, и его производительность определяется в первую очередь производительностью памяти. Таким образом, OpenMP просто распределил время ожидания доступа к памяти между различными процессами, а MPI добавил времени за счет выполнения передач между узлами.&lt;br /&gt;
&lt;br /&gt;
Метод create_adjacency_matrix также был распараллелен с помощью MPI. К качественному ускорению это не привело, в первую очередь из-за того, что на использованных тестах среднее время выполнения этого метода занимало около 0.004% от общего времени выполнения.&lt;br /&gt;
&lt;br /&gt;
Таким образом, попытки распараллеливания данной реализации алгоритма не привели к уменьшению времени ее работы, что согласуется с оценками параллельного ресурса самого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;br /&gt;
&lt;br /&gt;
[6] Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=17085</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=17085"/>
		<updated>2016-11-14T17:46:08Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Teplov}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Как показано на информационном графе, значительная часть алгоритма не предполагает параллельного выполнения. Взаимной независимостью обладают только фрагмент, где создаются локальные кучи, и ряд действий по перемещению точек между кучами.&lt;br /&gt;
&lt;br /&gt;
Для оценки производительности была выбрана реализация из [https://github.com/annoviko/pyclustering annoviko/pyclustering], выполненная на C++. Исходная версия алгоритма показала следующие результаты. Здесь и далее для тестирования использовался суперкомпьютер «Ломоносов» [6] [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Название теста&lt;br /&gt;
! Время выполнения (сек)&lt;br /&gt;
! Количество точек&lt;br /&gt;
! Количество кластеров&lt;br /&gt;
|-&lt;br /&gt;
| Chainlink&lt;br /&gt;
| 312.7&lt;br /&gt;
| 1500&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| TwoDiamonds&lt;br /&gt;
| 160.4&lt;br /&gt;
| 1270&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| Target&lt;br /&gt;
| 142.9&lt;br /&gt;
| 1150&lt;br /&gt;
| 6&lt;br /&gt;
|-&lt;br /&gt;
| WingNut&lt;br /&gt;
| 1324.6&lt;br /&gt;
| 2400&lt;br /&gt;
| 2&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Из всех методов, задействованных в реализации, возможности для параллельного выполнения включали два, calculate_links и create_adjacency_matrix. В обоих случаях были предприняты попытки использования этих возможностей.&lt;br /&gt;
&lt;br /&gt;
Метод calculate_links в оригинальной версии отвечал за 20-25% общего времени выполнения. После распараллеливания на OpenMP производительность только ухудшилась, тот же результат принесло использование MPI. Для наглядности исходный код метода приведен ниже.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
size_t rock::calculate_links(const cluster &amp;amp; cluster1, const cluster &amp;amp; cluster2) const {&lt;br /&gt;
    size_t number_links = 0;&lt;br /&gt;
    for (auto i : cluster1)&lt;br /&gt;
        for (auto j : cluster2)&lt;br /&gt;
            number_links += (size_t) m_adjacency_matrix.has_connection(i, j);&lt;br /&gt;
    return number_links;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как видно, проблема заключается в том, что метод практически не содержит вычислений, и его производительность определяется в первую очередь производительностью памяти. Таким образом, OpenMP просто распределил время ожидания доступа к памяти между различными процессами, а MPI добавил времени за счет выполнения передач между узлами.&lt;br /&gt;
&lt;br /&gt;
Метод create_adjacency_matrix также был распараллелен с помощью MPI. К качественному ускорению это не привело, в первую очередь из-за того, что на использованных тестах среднее время выполнения этого метода занимало около 0.004% от общего времени выполнения.&lt;br /&gt;
&lt;br /&gt;
Таким образом, попытки распараллеливания данной реализации алгоритма не привели к уменьшению времени ее работы, что согласуется с оценками параллельного ресурса самого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=17083</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=17083"/>
		<updated>2016-11-14T17:37:39Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Teplov}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
Как показано на информационном графе, значительная часть алгоритма не предполагает параллельного выполнения. Взаимной независимостью обладают только фрагмент, где создаются локальные кучи, и ряд действий по перемещению точек между кучами.&lt;br /&gt;
&lt;br /&gt;
Для оценки производительности была выбрана реализация из [https://github.com/annoviko/pyclustering annoviko/pyclustering], выполненная на C++. Исходная версия алгоритма показала следующие результаты. Здесь и далее для тестирования использовался суперкомпьютер «Ломоносов».&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Название теста&lt;br /&gt;
! Время выполнения (сек)&lt;br /&gt;
! Количество точек&lt;br /&gt;
! Количество кластеров&lt;br /&gt;
|-&lt;br /&gt;
| Chainlink&lt;br /&gt;
| 312.7&lt;br /&gt;
| 1500&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| TwoDiamonds&lt;br /&gt;
| 160.4&lt;br /&gt;
| 1270&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| Target&lt;br /&gt;
| 142.9&lt;br /&gt;
| 1150&lt;br /&gt;
| 6&lt;br /&gt;
|-&lt;br /&gt;
| WingNut&lt;br /&gt;
| 1324.6&lt;br /&gt;
| 2400&lt;br /&gt;
| 2&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Из всех методов, задействованных в реализации, возможности для параллельного выполнения включали два, calculate_links и create_adjacency_matrix. В обоих случаях были предприняты попытки использования этих возможностей.&lt;br /&gt;
&lt;br /&gt;
Метод calculate_links в оригинальной версии отвечал за 20-25% общего времени выполнения. После распараллеливания на OpenMP производительность только ухудшилась, тот же результат принесло использование MPI. Для наглядности исходный код метода приведен ниже.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot; line&amp;gt;&lt;br /&gt;
size_t rock::calculate_links(const cluster &amp;amp; cluster1, const cluster &amp;amp; cluster2) const {&lt;br /&gt;
    size_t number_links = 0;&lt;br /&gt;
    for (auto i : cluster1)&lt;br /&gt;
        for (auto j : cluster2)&lt;br /&gt;
            number_links += (size_t) m_adjacency_matrix.has_connection(i, j);&lt;br /&gt;
    return number_links;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Как видно, проблема заключается в том, что метод практически не содержит вычислений, и его производительность определяется в первую очередь производительностью памяти. Таким образом, OpenMP просто распределил время ожидания доступа к памяти между различными процессами, а MPI добавил времени за счет выполнения передач между узлами.&lt;br /&gt;
&lt;br /&gt;
Метод create_adjacency_matrix также был распараллелен с помощью MPI. К качественному ускорению это не привело, в первую очередь из-за того, что на использованных тестах среднее время выполнения этого метода занимало около 0.004% от общего времени выполнения.&lt;br /&gt;
&lt;br /&gt;
Таким образом, попытки распараллеливания данной реализации алгоритма не привели к уменьшению времени ее работы, что согласуется с оценками параллельного ресурса самого алгоритма.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=14421</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=14421"/>
		<updated>2016-10-28T13:01:54Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Teplov&amp;diff=13832</id>
		<title>Обсуждение участника:Teplov</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:Teplov&amp;diff=13832"/>
		<updated>2016-10-26T06:40:30Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: Новая страница: «Добрый день! Замечания к статье исправлены (Участники: Круглов Леонид, Баранов Максим/Ал…»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Добрый день! Замечания к статье исправлены (Участники: Круглов Леонид, Баранов Максим/Алгоритм устойчивой кластеризации с использованием связей)&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13831</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13831"/>
		<updated>2016-10-26T06:38:33Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK_graph.png|400px|thumb|right|Визуализация информационного графа для n = 100 исходных точек и k = 8 требуемых кластеров]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13830</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13830"/>
		<updated>2016-10-26T06:34:53Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;QS&#039;&#039;&#039; - созданиение локальной кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
* &#039;&#039;&#039;K&#039;&#039;&#039; - полученный кластер&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13621</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13621"/>
		<updated>2016-10-24T22:05:59Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13620</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13620"/>
		<updated>2016-10-24T22:04:44Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13619</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13619"/>
		<updated>2016-10-24T22:03:30Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оценка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13618</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13618"/>
		<updated>2016-10-24T22:03:18Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13617</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13617"/>
		<updated>2016-10-24T22:02:50Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13616</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13616"/>
		<updated>2016-10-24T22:02:05Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13609</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13609"/>
		<updated>2016-10-24T20:33:02Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если для вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13608</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13608"/>
		<updated>2016-10-24T20:30:56Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если в качестве алгоритма вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным.&lt;br /&gt;
&lt;br /&gt;
Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - сложность параллельного алгоритма подсчета числа связей (оценки приведены для использования алгоритма Копперсмита—Винограда для вычисления количества связей).&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13607</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13607"/>
		<updated>2016-10-24T20:18:12Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если в качестве алгоритма вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13606</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13606"/>
		<updated>2016-10-24T20:14:31Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n^{2,37} + n^2\log n)&amp;lt;/math&amp;gt;, если в качестве алгоритма вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13605</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13605"/>
		<updated>2016-10-24T20:05:01Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;\frac{O(n^{2,37} + n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;, если в качестве алгоритма вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13604</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=13604"/>
		<updated>2016-10-24T20:00:49Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм устойчивой кластеризации с использованием связей&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;\frac{O(n^{2,37}) + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;, если в качестве алгоритма вычисления количества связей используется алгоритм Копперсмита—Винограда&lt;br /&gt;
| input_data        = Вектор из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек в виде векторов характеристик произвольного вида, дополнительно одно вещественное и одно челое число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = Сгруппированные в &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; классифицируемых точек представленных индексами во входном векторе&lt;br /&gt;
}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1] (псевдокод):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_t = O(n^{2,37} + n^2\log{n})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Пороговое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=12067</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=12067"/>
		<updated>2016-10-15T20:59:59Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_t = C_L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=12043</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=12043"/>
		<updated>2016-10-15T20:57:09Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:LKruglov|Круглов Л. В.]](1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_t = C_L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=12039</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=12039"/>
		<updated>2016-10-15T20:56:38Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:LKruglov|Круглов Л. В.]]1.1,1.2,1.3,1.6,1.8,1.10), [[Участник:Innot|Баранов М. С.]](1.1,1.2,1.3,1.4,1.5,1.7,1.9,2.7)&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_t = C_L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_{t_p} = {C_{L_p}} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{C_{L_p}}&amp;lt;/math&amp;gt; - оцентка времени работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{C_L + O(n^2\log n)}{{C_{L_p}} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;C_{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11931</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11931"/>
		<updated>2016-10-15T20:45:30Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Программная реализация алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, оценка времени выполнения алгоритма &amp;lt;math&amp;gt;C_t&amp;lt;/math&amp;gt; задается следующей формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_t = C_L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;C_L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и задается формулой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;C_s = O(min(n^2, n{m_m}{m_a}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11878</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11878"/>
		<updated>2016-10-15T20:41:17Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Входные и выходные данные алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, временная сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и также равняется &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, распределенных по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11858</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11858"/>
		<updated>2016-10-15T20:38:34Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей:&lt;br /&gt;
# Подсчет количества связей между точками;&lt;br /&gt;
# Итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, временная сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и также равняется &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11841</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11841"/>
		<updated>2016-10-15T20:36:13Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, временная сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и также равняется &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление кучи/куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11837</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11837"/>
		<updated>2016-10-15T20:35:43Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятий связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров работа алгоритма завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, временная сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
Пространственную сложность подсчета количества связей можно оценить как &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;. Так как при слиянии двух кластеров размер новой кучи не превосходит суммы размеров куч объединяемых кластеров, то пространственная сложность итерационной части алгоритма зависит только от размеров исходных куч и также равняется &amp;lt;math&amp;gt;O(min(n^2, n{m_m}{m_a})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
[[Файл:ROCK.info.graph.png|400px|thumb|right|Визуализация информационного графа]]&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Используются следующие обозначения.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039; - входные данные&lt;br /&gt;
* &#039;&#039;&#039;M&#039;&#039;&#039; - вычисление матрицы связей&lt;br /&gt;
* &#039;&#039;&#039;Qs&#039;&#039;&#039; - вычисление локальных кучи&lt;br /&gt;
* &#039;&#039;&#039;QG&#039;&#039;&#039; - создание глобальной кучи&lt;br /&gt;
* &#039;&#039;&#039;HG&#039;&#039;&#039; - взятие элемента/элементов из кучи&lt;br /&gt;
* &#039;&#039;&#039;HD&#039;&#039;&#039; - удаление элемента из кучи&lt;br /&gt;
* &#039;&#039;&#039;HI&#039;&#039;&#039; - добавление элемента в кучу&lt;br /&gt;
* &#039;&#039;&#039;HU&#039;&#039;&#039; - обновление кучи&lt;br /&gt;
* &#039;&#039;&#039;HX&#039;&#039;&#039; - удаление кучи/куч&lt;br /&gt;
* &#039;&#039;&#039;CM&#039;&#039;&#039; - слияние кластеров&lt;br /&gt;
* &#039;&#039;&#039;A&#039;&#039;&#039; - арифметические операции&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11774</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11774"/>
		<updated>2016-10-15T20:24:05Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3&lt;br /&gt;
# Пакет [https://cran.r-project.org/web/packages/cba/index.html CBA]  из репозитория CRAN содержит реализацию на R под GPL 2&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11753</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11753"/>
		<updated>2016-10-15T20:21:00Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Литература */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1] Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2] Coppersmith D., Winograd S. Matrix multiplication via arithmetic progressions //Proceedings of the nineteenth annual ACM symposium on Theory of computing. – ACM, 1987. – С. 1-6.&lt;br /&gt;
&lt;br /&gt;
[3] Thomas H. Cormen et al. Introduction to algorithms. – Cambridge : MIT press, 2001. – Т. 6.&lt;br /&gt;
&lt;br /&gt;
[4] Guha S., Rastogi R., Shim K. Cure: an efficient clustering algorithm for large databases //Information Systems. – 2001. – Т. 26. – №. 1. – С. 35-58.&lt;br /&gt;
&lt;br /&gt;
[5] Vitter J. S. Random sampling with a reservoir //ACM Transactions on Mathematical Software (TOMS). – 1985. – Т. 11. – №. 1. – С. 37-57.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11722</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11722"/>
		<updated>2016-10-15T20:15:24Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда [2], вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1]Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2]&lt;br /&gt;
&lt;br /&gt;
[3]&lt;br /&gt;
&lt;br /&gt;
[4]&lt;br /&gt;
&lt;br /&gt;
[5]&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11719</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11719"/>
		<updated>2016-10-15T20:14:47Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Литература */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [2] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
[1]Guha S., Rastogi R., Shim K. ROCK: A robust clustering algorithm for categorical attributes //Data Engineering, 1999. Proceedings., 15th International Conference on. – IEEE, 1999. – С. 512-521.&lt;br /&gt;
&lt;br /&gt;
[2]&lt;br /&gt;
&lt;br /&gt;
[3]&lt;br /&gt;
&lt;br /&gt;
[4]&lt;br /&gt;
&lt;br /&gt;
[5]&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11701</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11701"/>
		<updated>2016-10-15T20:13:04Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [2] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [4]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [5].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11690</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11690"/>
		<updated>2016-10-15T20:12:16Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [2] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [3]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [5]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [6].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11683</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11683"/>
		<updated>2016-10-15T20:11:40Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Свойства и структура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым [1].&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [3] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [4]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [5]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [6].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11677</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11677"/>
		<updated>2016-10-15T20:10:45Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Свойства и структура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK [1]) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым.&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [3] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [4]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [5]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [6].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11670</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11670"/>
		<updated>2016-10-15T20:10:01Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Программная реализация алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым.&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [3] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [4]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [5]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [6].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11663</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11663"/>
		<updated>2016-10-15T20:09:25Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым.&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [3] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [4]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [5]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [6].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11645</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11645"/>
		<updated>2016-10-15T20:06:24Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым.&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [3] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество кластеризуемых точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [4]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [5]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [6].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11641</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11641"/>
		<updated>2016-10-15T20:05:17Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым.&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [3] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [4]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [5]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [6].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11638</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11638"/>
		<updated>2016-10-15T20:05:05Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым.&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}} \qquad(1)&amp;lt;/math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [3] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [4]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [5]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [6].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11634</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11634"/>
		<updated>2016-10-15T20:04:51Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым.&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}}&amp;lt;/math&amp;gt; \qquad(1)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [3] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [4]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [5]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [6].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11616</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11616"/>
		<updated>2016-10-15T20:02:42Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым.&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}}&amp;lt;/math&amp;gt; (1)&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [3] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [4]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма. В таком случае при распараллеливании алгоритма на &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; вычислительных узлов верна следующая оценка времени работы алгоритма:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{L_p} + O(\frac{n^2\log n}{p})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - время работы выбранного параллельного алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [5]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [6].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11599</id>
		<title>Участник:LKruglov/Алгоритм устойчивой кластеризации с использованием связей</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:LKruglov/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%83%D1%81%D1%82%D0%BE%D0%B9%D1%87%D0%B8%D0%B2%D0%BE%D0%B9_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9&amp;diff=11599"/>
		<updated>2016-10-15T19:58:18Z</updated>

		<summary type="html">&lt;p&gt;Lkruglov: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Общее описание алгоритма ==&lt;br /&gt;
=== Свойства и структура алгоритма ===&lt;br /&gt;
В связи с наличием огромного количества накопленной информации задача добычи данных становится все более важной. Кластеризация позволяет распределять данные по группам (кластрерам) так, что в каждой группе данные обладают схожими характеристиками, а в разных группах характеристики различаются.&lt;br /&gt;
&lt;br /&gt;
Алгоритм устойчивой кластеризации с использованием связей (robust clustering using links, ROCK) построен на основе понятия связей между кластеризуемыми точками и их соседства. Две точки считаются соседями, если являются достаточно близким (схожими): &amp;lt;math&amp;gt;sim({p_i}, {p_j}) &amp;gt;= \theta&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; - заданное пороговое значение в интервале &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;. Связь &amp;lt;math&amp;gt;link({p_i}, {p_j})&amp;lt;/math&amp;gt; между двумя точками определяется как число общих соседей между точками &amp;lt;math&amp;gt;{p_i}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{p_j}&amp;lt;/math&amp;gt;. Таким образом, чем большее значение функции связи для двух точек, тем более вероятно они принадлежат одному кластеру.&lt;br /&gt;
&lt;br /&gt;
В отличие от алгоритмов кластеризации, учитывающих только локальные характеристики точек, данный алгоритм учитывает глобальную информацию о соседстве при принятии решений о выделении кластеров, что делает его очень устойчивым.&lt;br /&gt;
&lt;br /&gt;
ROCK принадлежит к классу иерархических алгоритмов кластеризации. На первом этапе работы алгоритма происходит определение соседей для каждой точки и подсчет количества связей для каждой пары точек. Изначально каждая точка рассматривается в качестве отдельного кластера и для каждого такого кластера рассчитываются значения функции качества,которые используются при последующем слиянии кластеров. Далее в ходе итерационного процесса на каждом шаге выбираются и объединяются два кластера и пересчитываются количество связей и функции качества для нового кластера. По достижении требуемого числа кластеров алгоритм завершается.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Задача кластеризации сводится к выделению такого разбиения точек на кластеры, которое максимизирует сумму связей точек принадлежащих одному кластеру, и минимизирует эту функцию для точек из разных кластеров. Таким образом, для разбияния на &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров необходима максимизация следующей функции.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E_l = \sum_{i=1}^k n_i * \sum_{p_q, p_r \in C_i} \frac{link(p_q, p_r)}{n_i^{1+2f(\theta)}}&amp;lt;/math&amp;gt; (1)&lt;br /&gt;
&lt;br /&gt;
Данная функция отличается от простой суммы связей для каждого кластера, так как не обеспечивает распределение точек, имеющих мало связей между собой, по разным кластерам. Поэтому действительную сумму связей в кластере следует разделить на ожидаемую сумму связей. Функция &amp;lt;math&amp;gt;f(\theta)&amp;lt;/math&amp;gt; задается пользователем исходя из свойств обрабатываемых данных и ожидаемого характера кластеризации. Она должна обладать следующим свойством: каждая точка, принадлежащая кластеру &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt;, имеет приблизительно &amp;lt;math&amp;gt;n_i^{f(\theta)}&amp;lt;/math&amp;gt; соседей в этом кластере.&lt;br /&gt;
&lt;br /&gt;
Связь между двумя кластерами определяется как&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;link({C_i}, {C_j}) = \sum^{}_{{p_q}\in{C_i}, {p_r}\in{C_j}}{link[{C_i}, {C_j}]}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для выбора кластеров для объединения определяется целевая функция качества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;g(C_i, C_j) = \frac{link[C_i, C_j]}{(n_i+n_j)^{1+2f(\theta)} - f_i^{1+2f(\theta)} - f_j^{1+2f(\theta)}}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично целевой функции (1) значение связи между двумя кластерами делится на ожидаемое число связей между кластерами.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительное ядро алгоритма состоит из двух частей: подсчет количества связей между точками и итеративное объединение кластеров.&lt;br /&gt;
&lt;br /&gt;
Один из возможных подходов к подсчету количества связей основывается на матрице смежности точек: достаточно умножить матрицу смежности на себя, и тогда каждая клетка полученной матрицы будет содержать число связей соответствующей точки.&lt;br /&gt;
&lt;br /&gt;
Итеративная часть алгоритма может быть реализована с помощью структуры данных куча. На каждой итерации с каждым кластером &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; связана своя куча &amp;lt;math&amp;gt;q[i]&amp;lt;/math&amp;gt;, содержащая все связанный с ним кластеры, упорядоченная по убыванию функции качества. Также поддерживается глобальная куча &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt;, содержащая все кластеры &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, упорядоченные по мере убывания функции качества &amp;lt;math&amp;gt;g(j, max(q[j]))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;max(q[j])&amp;lt;/math&amp;gt; - это вершина кучи &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. Тогда на каждой итерации объединяются кластер &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; с вершины глобальной кучи и кластер &amp;lt;math&amp;gt;q[j]&amp;lt;/math&amp;gt;. После объединения необходимо обновить все кучи, содержащие объединенные кластеры, обновить глобальную кучу &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; и создать кучу для нового кластера. Итеративный процесс продолжается до тех пор, пока в глобальной куче &amp;lt;math&amp;gt;Q&amp;lt;/math&amp;gt; не останется требуемое число кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как было описано выше, основную часть каждой итерации алгоритма составляет обновление куч, содержащих сливаемые кластеры.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
Следующая схема последовательного алгоритма представлена в работе [1]:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line&amp;gt;&lt;br /&gt;
procedure cluster(S, k)&lt;br /&gt;
begin&lt;br /&gt;
    link := compute_links(S)&lt;br /&gt;
    for s in S do&lt;br /&gt;
    begin&lt;br /&gt;
        q[s] := build_local_heap(link, s)&lt;br /&gt;
    end&lt;br /&gt;
    Q := build_global_heap(S, q)&lt;br /&gt;
    while size(Q) &amp;gt; k do&lt;br /&gt;
    begin&lt;br /&gt;
        u := extract_max(Q)&lt;br /&gt;
        v := max(q[u])&lt;br /&gt;
        delete(Q, v)&lt;br /&gt;
        w := merge(u, v)&lt;br /&gt;
        for each x in q[u] or q[v] do&lt;br /&gt;
        begin&lt;br /&gt;
            link[x, w] := link[x, u] + link[x, v]&lt;br /&gt;
            delete(q[x], u)&lt;br /&gt;
            delete(q[x], v)&lt;br /&gt;
            insert(q[x], w, g(x, w))&lt;br /&gt;
            insert(q[w], x, g(x, w))&lt;br /&gt;
            update(Q, x, q[x])&lt;br /&gt;
        end&lt;br /&gt;
        insert(Q, w, q[w])&lt;br /&gt;
        deallocate(q[u])&lt;br /&gt;
        deallocate(q[v])&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Для вычисления количества связей с помощью возведения матрицы в квадрат можно воспользоваться алгоритмом Копперсмита—Винограда, вычислительная сложность которого равна &amp;lt;math&amp;gt;O(n^{2,37})&amp;lt;/math&amp;gt; [3] (&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - количество точек). Для случаев разреженной матрицы смежности в работе [1] описывается алгоритм, имеющий сложность &amp;lt;math&amp;gt;O(n^2 + n{m_m}{m_a})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{m_a}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{m_m}&amp;lt;/math&amp;gt; - это среднее и максимальное количество соседей точки соответственно.&lt;br /&gt;
&lt;br /&gt;
Каждая куча может быть построена за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; [4]. Внешний цикл итерационной части алгоритма исполняется &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; раз. Так как на очередной итерации размер каждой локальной кучи в худшем случае может равняться &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, то новый кластер должен быть помещен в &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; локальных куч, что дает временную сложность вложенного цикла &amp;lt;math&amp;gt;O(n\log{n})&amp;lt;/math&amp;gt;. Таким образом, сложность внешнего цикла в худшем случае будет &amp;lt;math&amp;gt;O(n^2\log{n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итак, сложность описанного алгоритма будет&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L + O(n^2\log{n})&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; - сложность алгоритма вычисления количества связей.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
На рисунке представлен информационный граф алгоритма. Блок L соответствует предварительному подсчету числа связей точек, блок QLs и QG - созданию локальных и глобальной куч соответственно, блок M - слиянию кластеров, блок U - обновлению куч.&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В описанном последовательном алгоритме основной ресурс параллелизма заключается в возможности параллельного вычисления количества связей (например, используя алгоритм параллельного вычисления произведения матриц), создания очередей, и параллельной обработки локальных очередей во внутреннем цикле итерационного этапа алгоритма.&lt;br /&gt;
&lt;br /&gt;
TODO?&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные:&lt;br /&gt;
&lt;br /&gt;
 1. Множество &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; точек, которые необходимо кластеризовать&lt;br /&gt;
 2. Порогрвое значение &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt; из интервала &amp;lt;math&amp;gt;(0, 1)&amp;lt;/math&amp;gt;&lt;br /&gt;
 3. Требуемое число кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также к входным данным относится информация о характеристиках точек (например в виде таблицы булевых значений принадлежности характеристик точкам).&lt;br /&gt;
&lt;br /&gt;
Выходные данные:&lt;br /&gt;
&lt;br /&gt;
 1. &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; полученных кластеров&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
Одним из важных вопросов, влияющих на эффективность алгоритма, является выбор исходных точек. Подход к выбору размера исходного набора точек, достаточного для качественной кластеризации, описывается в работе [5]. Использование случайной стратегии выбора исходных точек помогает алгоритму кластеризации отбрасыванием выпадающих точек (то есть точек, слабо связанных с другими точками). Различные алгоритмы случайного выбора исходных точек рассматриваются в работе [6].&lt;br /&gt;
&lt;br /&gt;
Обработка выпадающих точек в рассматриваемом алгоритме обеспечивается выбором порогового значения &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;. Также такие точки могут быть принудительно отброшены на последних итерациях алгоритма.&lt;br /&gt;
&lt;br /&gt;
После завершения кластеризации выбранных исходных точек, оставшиеся точки распределяются по кластерам следующим образом. Из каждого кластера выбирается набор точек &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;, и очередная точка &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; помещается в кластер &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; имеет наибольшее число соседей множеством &amp;lt;math&amp;gt;{L_i}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассматриваемый алгоритм является детерминированным. Его вычислительная мощность равна&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{2n+2}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
отношение последовательной и параллельной сложности:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{L + O(n^2\log n)}{{L_p} + O(\frac{n^2\log n}{p})}&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{L_p}&amp;lt;/math&amp;gt; - соответственно последовательная и параллельная сложность алгоритма подсчета числа связей.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Библиотека [https://github.com/annoviko/pyclustering annoviko/pyclustering] включает реализации для Python и C++ под GPL 3.&lt;br /&gt;
# Пакет CBA из репозитория CRAN содержит реализацию на R под GPL 2: [https://cran.r-project.org/web/packages/cba/index.html]&lt;br /&gt;
# Библиотеки [http://www.cs.waikato.ac.nz/ml/weka/ Weka] и [https://sourceforge.net/projects/feed4weka/files/?source=navbar feed4weka] содержат реализацию для Java под GPL 2.&lt;/div&gt;</summary>
		<author><name>Lkruglov</name></author>
	</entry>
</feed>